2017-09-19 14 views
4

リクエストオブジェクトから起動された複数の非同期タスクを反復し、両方のリクエストに依存する他の非同期タスクを実行する最も効率的な方法を正しく設計しようとすると、オブジェクトと最初の非同期タスクの結果を返します。私はAWSでC#ラムダ関数を実行しています。私は、C#For Each Loop with ASyncタスクとDependent Post ASyncタスク

public async Task MyAsyncWrapper() 
{ 
    List<Task> Tasks = new List<Task>(); 
    foreach (var Request in Requests) 
    { 
    var Continuation = this.ExecuteAsync(Request).ContinueWith(async x => { 
     var KeyValuePair<bool, string> Result = x.Result; 
     if (Result.Key == true) 
     { 
     await this.DoSomethingElseAsync(Request.Id, Request.Name, Result.Value); 
     Console.WriteLine("COMPLETED"); 
     } 
    } 

    Tasks.Add(Continuation); 
    } 

    Task.WaitAll(Tasks.ToArray()); 
} 

このアプローチDoSomethingElseAsync()方法の結果は本当に私のラムダ関数呼び出しのロットとで待っ得ていない:私はこの(エラー処理などを簡潔にするため省略されている)のようなモデルを試してみました"COMPLETED"出力を得ることはありません。

public async Task MyAsyncWrapper() 
{ 
    foreach (var Request in Requests) 
    { 
    KeyValuePair<bool, string> Result = await this.ExecuteAsync(Request); 

    if (Result.Key == true) 
    { 
     await this.DoSomethingElseAsync(Request.Id, Request.Name, Result.Value); 
     Console.WriteLine("COMPLETED"); 
    } 
    } 
} 

これは動作しますが、私は唯一のループの1回の繰り返しを実行することができるのでasnycの終了するのを待っている間、それは、無駄だと思う:私はまた、この方法でこれを近づいてきました。私もInterleaved Tasksを参照していますが、問題は基本的には2つのループ、1つはタスクを設定するループ、もう1つは完了した後に反復することです。これは元のRequestオブジェクトにアクセスできません。したがって、基本的には

List<Task<KeyValuePair<bool, string>>> Tasks = new List<Task<KeyValuePair<bool, string>>>(); 

foreach (var Request in Requests) 
{ 
    Tasks.Add(ths.ExecuteAsync(Request); 
} 

foreach (Task<KeyValuePair<bool, string>> ResultTask in Tasks.Interleaved()) 
{ 
    KeyValuePair<bool, string> Result = ResultTask.Result; 
    //Can't access the original request for this method's parameters 
    await this.DoSomethingElseAsync(???, ???, Result.Value); 
} 

このタイプの非同期チェインをforeachループで実装するための良いアイデアはありますか?私の理想的なアプローチは、ExecuteAsync()からの応答の一部として要求オブジェクトを戻すことではないので、可能ならば他のオプションも試してみたいと思います。

答えて

3

私は誤解が、なぜそれ自身の機能の中に、あなたの「反復」に移動して、並列にすべての反復を待つTask.WhenAllを使用しないことがあります。

public async Task MyAsyncWrapper() 
{ 
    var allTasks = Requests.Select(ProcessRequest); 

    await Task.WhenAll(allTasks); 
} 

private async Task ProcessRequest(Request request) 
{ 
    KeyValuePair<bool, string> Result = await this.ExecuteAsync(request); 

    if (Result.Key == true) 
    { 
     await this.DoSomethingElseAsync(request.Id, request.Name, Result.Value); 
     Console.WriteLine("COMPLETED"); 
    } 
} 
+0

これは本当に役に立つかもしれないと思います。私はそれを試してみると、それが動作するかどうかを確認します。 – hakenmt

+0

このソリューションは私のために働き、複数の異なる要求タイプに対してこれらのループを実行するために書いたコード量を大幅に削減しました。 – hakenmt

3

はTPLデータフローを使用することを検討してください:

var a = new TransformBlock<Input, OutputA>(async Input i=> 
{ 
    // do something async. 
    return new OutputA(); 
}); 

var b = new TransformBlock<OutputA, OutputB>(async OutputA i => 
{ 
    // do more async. 
    return new OutputB(); 
}); 

var c = new ActionBlock<OutputB>(async OutputB i => 
{ 
    // do some final async. 
}); 

a.LinkTo(b, new DataflowLinkOptions { PropogateCompletion = true }); 
b.LinkTo(c, new DataflowLinkOptions { PropogateCompletion = true }); 

// push all of the items into the dataflow. 
a.Post(new Input()); 
a.Complete(); 

// wait for it all to complete. 
await c.Completion; 
+0

だから私はどのようにこの本は、アクションの単鎖のために働くことができる方法を見て、私は、各 'Cを確保することができるように' Input'は 'Request'あるforeachループで期待どおりに、この作品がします'メソッドを終了する前に完了しましたか? – hakenmt

+0

これは 'foreach'ループに取って代わるものです。あなたのコードをループの中に入れるのではなく、あなたのループは単にデータを' Post'データにするだけです。 –

関連する問題