簡體   English   中英

C#ForEach循環具有ASync任務和相關的后期ASync任務

[英]C# ForEach Loop With ASync Tasks & Dependent Post ASync Tasks

我無法正確地構建最有效的方法來迭代從請求對象啟動的幾個異步任務,然后執行一些依賴於請求對象和第一個異步任務的結果的其他異步任務。 我正在AWS中運行C#lambda函數。 我嘗試過這樣的模型(為簡潔起見,省略了錯誤處理等):

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()方法沒有真正等待我的Lambda函數調用,我從來沒有得到“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");
    }
  }
}

這是有效的,但我認為這很浪費,因為我只能在等待asnyc完成時執行循環的一次迭代。 我也引用了Interleaved Tasks,但問題是我基本上有兩個循環,一個用於填充任務,另一個用於在完成后迭代它們,在那里我不再能夠訪問原始的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()響應的一部分返回,所以我想盡可能嘗試找到其他選項。

考慮使用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;

我可能會誤解,但為什么不將你的“迭代”移動到它自己的函數中,然后使用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");
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM