1

非同期メソッドを使用して複数のソースからデータをロードするコードがあります (以下を参照)。

public class ThEnvironment
{
    public async Task LoadLookupsAsync(CancellationToken cancellationToken) { ... }
    public async Task LoadFoldersAsync(CancellationToken cancellationToken) { ... }
}

プログラムの他の場所で、複数の環境をロードしたいと考えています。

ThEnvironment[] workingEnvironments = ThEnvironment.Manager.GetWorkingEnvironments();
foreach ( ThEnvironment environment in workingEnvironments )
{
    await environment.LoadLookupsAsync(CancellationToken.None);
    await environment.LoadFoldersAsync(CancellationToken.None);
}

私の質問は 2 つあります。

  1. 単一の環境で、両方の environment.Load...Async() メソッドを並行して実行し、CancellationToken を渡すにはどうすればよいですか?
  2. すべての環境でこれを並行して行うにはどうすればよいですか?

結論: すべての環境ですべての Load..Async() メソッドを並行して実行し、それでも CancellationToken を渡すことができるようにしたいと考えています。


アップデート

非常に迅速な回答をありがとうございました。コードを次のように減らしました。

Refresh();

var tasks = ThEnvironment.Manager.GetWorkingEnvironments()
    .SelectMany(e => new Task[] { e.LoadLookupsAsync(CancellationToken.None), e.LoadFoldersAsync(CancellationToken.None) });

await Task.WhenAll(tasks.ToArray());

これは本番アプリケーションではないため、すべての例外をキャプチャすることについてあまり心配していません。上部の Refresh() は、フォームの最初の描画の問題を処理しました。

素晴らしいもの。

4

2 に答える 2

2

単純に両方Taskの を開始し、両方が完了するのを待ちます。

Task lookupsTask = environment.LoadLookupsAsync(cancellationToken);
Task foldersTask = environment.LoadFoldersAsync(cancellationToken);

await lookupsTask;
await foldersTask;

同じコードのより効率的なバージョンは、次を使用することTask.WhenAll()です。

await Task.WhenAll(lookupsTask, foldersTask);

Task2 つだけでなく、 のコレクションに対してこれを行いたい場合は、 aList<Task>をすべての で埋めてTaskからawait Task.WhenAll(tasksList).

このアプローチの問題点の 1 つは、複数の例外が発生した場合、最初の例外しか取得できないことです。それが問題である場合は、280Z28 が提案したようなものを使用できます。

于 2013-11-08T17:15:36.317 に答える
1

同じキャンセル トークンを使用して両方のアクションを開始し、両方が完了するまで待ちます。

Task lookupsTask = environment.LoadLookupsAsync(cancellationToken);
Task foldersTask = environment.LoadFoldersAsync(cancellationToken);

await Task.Factory.ContinueWhenAll(
    new[] { lookupsTask, foldersTask },
    TaskExtrasExtensions.PropagateExceptions,
    TaskContinuationOptions.ExecuteSynchronously);

これはPropagateExceptions、Parallel Extensions Extras サンプル コードの拡張メソッドを使用して、ロード タスクからの例外情報が失われないようにします。

/// <summary>Propagates any exceptions that occurred on the specified tasks.</summary>
/// <param name="tasks">The Task instances whose exceptions are to be propagated.</param>
public static void PropagateExceptions(this Task [] tasks)
{
    if (tasks == null) throw new ArgumentNullException("tasks");
    if (tasks.Any(t => t == null)) throw new ArgumentException("tasks");
    if (tasks.Any(t => !t.IsCompleted)) throw new InvalidOperationException("A task has not completed.");
    Task.WaitAll(tasks);
}
于 2013-11-08T16:21:11.733 に答える