Dot-Net

如何將“Where”與非同步謂詞一起使用?

  • February 15, 2013

我有一個這樣的非同步謂詞方法:

private async Task<bool> MeetsCriteria(Uri address)
{
   //Do something involving awaiting an HTTP request.
}

假設我有一個Uris 集合:

var addresses = new[]
{
   new Uri("http://www.google.com/"),
   new Uri("http://www.stackoverflow.com/") //etc.
};

我想addresses使用MeetsCriteria. 我想非同步執行此操作;我希望對謂詞的多次呼叫非同步執行,然後我想等待它們全部完成並生成過濾後的結果集。不幸的是,LINQ 似乎不支持非同步謂詞,所以這樣的事情不起作用

var filteredAddresses = addresses.Where(MeetsCriteria);

有沒有類似方便的方法來做到這一點?

我認為框架中沒有這樣的原因之一是存在很多可能的變化,並且在某些情況下每個選擇都是正確的:

  • 謂詞應該並行執行還是串列執行?

    • 如果它們並行執行,是應該全部同時執行,還是應該限制並行度?

    • 如果它們並行執行,結果應該與原始集合的順序相同、完成順序還是未定義順序?

      • 如果它們應該按完成的順序返回,是否應該有某種方法(非同步)在它們完成時獲取結果?(這需要將返回類型從更改為Task<IEnumerable<T>其他類型。)

您說您希望謂詞並行執行。在這種情況下,最簡單的選擇是一次執行它們並按完成順序返回它們:

static async Task<IEnumerable<T> Where<T>(
   this IEnumerable<T> source, Func<T, Task<bool> predicate)
{
   var results = new ConcurrentQueue<T>();
   var tasks = source.Select(
       async x =>
       {
           if (await predicate(x))
               results.Enqueue(x);
       });
   await Task.WhenAll(tasks);
   return results;
}

然後你可以像這樣使用它:

var filteredAddresses = await addresses.Where(MeetsCriteria);

引用自:https://stackoverflow.com/questions/14889988