いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

タスク並列ライブラリ入門記-008 (Taskから結果を取得, Task.Result)

タスクからの結果取得について。

タスクから結果を取得するにはタスク生成時にFuncオブジェクトを指定します。 その後、実行してResultプロパティを参照すれば結果が取得できます。

非同期処理なので、当然まだ処理が完了していない場合があります。 その場合、Resultプロパティは結果が取得できるまでブロックされます。

注意点として、非同期処理中に例外が発生していた場合 Resultプロパティにアクセスした時点で例外(AggregateExcepiton)が発生します。

以下、サンプルです。

namespace Sazare.Samples
{
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Threading;
  using System.Threading.Tasks;

  using Sazare.Common;

  /// <summary>
  /// タスク並列ライブラリについてのサンプルです。
  /// </summary>
  /// <remarks>
  /// タスク並列ライブラリは、.NET 4.0から追加されたライブラリです。
  /// </remarks>
  [Sample]
  class TaskSamples07 : IExecutable
  {
    public void Execute()
    {
      //
      // タスクの戻り値は
      //   Resultプロパティ
      // から取得できる。
      //
      // 非同期処理内で例外が発生していた場合
      // Resultプロパティにアクセスした段階で
      // 例外 (AggregateException) が発生するので注意。
      //
      // タスクにて、内部で例外が発生していた場合に
      // 以下のメソッドにアクセスすると保留されていた
      // 例外が発生する.
      //
      //   ・Resultプロパティ
      //   ・Waitメソッド
      //

      //
      // 以下、いろいろな方法でタスクを作成して結果を取得.
      //
      var task1 = Task.Run(() => GetStringResult());
      Output.WriteLine(task1.Result);

      var task2 = Task.Factory.StartNew(() => GetIntResult());
      Output.WriteLine(task2.Result);

      var task3 = new Task<string>(() => GetStringResult());
      task3.Start();
      Output.WriteLine(task3.Result);

      var tokenSource = new CancellationTokenSource();
      var task4       = Task.Run(() => GetDelayResult(tokenSource.Token), tokenSource.Token);
      try
      {
        //
        // 指定時間後にキャンセル.
        //   CancellationTokenSource.Cancelで発生する例外は
        //   OperationCanceledExceptionだが
        //   タスクに対して、予め同じキャンセルトークンを渡している場合
        //   キャンセル例外が発生したことをタスクが認識して
        //   TaskCanceledExceptionを発生させる.
        //
        tokenSource.CancelAfter(TimeSpan.FromMilliseconds(500));
        Output.WriteLine(task4.Result);
      }
      catch (AggregateException aggreEx)
      {
        aggreEx.Handle(ex => 
          {
            if (ex is TaskCanceledException)
            {
              Output.WriteLine("[CANCEL] {0}", ex);
              return true;
            }

            return false;
          });
      }
    }

    internal int GetIntResult()
    {
      return 100;
    }

    internal string GetStringResult()
    {
      return "Hello world";
    }

    internal async Task<string> GetDelayResult(CancellationToken token)
    {
      await Task.Delay(TimeSpan.FromMilliseconds(5000));
      token.ThrowIfCancellationRequested();
      return GetStringResult();
    }
  }
}

実行すると以下のようになります。

Hello world
100
Hello world
[CANCEL] System.Threading.Tasks.TaskCanceledException: タスクが取り消されました。

過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。