Async在linq select中等待
我需要修改一个现有的程序,它包含以下代码:
var inputs = events.Select(async ev => await ProcessEventAsync(ev)) .Select(t => t.Result) .Where(i => i != null) .ToList();  但是这对我来说似乎很奇怪,首先在select中使用async和await 。 根据Stephen Cleary的这个答案 ,我应该可以放弃这些。 
 然后Select第二个Select结果。 这是不是意味着这个任务不是asynchronous的,并且是同步执行的(这么多努力),或者这个任务是asynchronous执行的,而当它完成时,执行其余的查询。 
我应该按照斯蒂芬·克里里的另一个答案来写下面的代码:
 var tasks = await Task.WhenAll(events.Select(ev => ProcessEventAsync(ev))); var inputs = tasks.Where(result => result != null).ToList(); 
这是完全一样的吗?
 var inputs = (await Task.WhenAll(events.Select(ev => ProcessEventAsync(ev)))) .Where(result => result != null).ToList(); 
虽然我在这个项目上工作,但我想改变第一个代码示例,但我并不太热衷于改变(exception工作)的asynchronous代码。 也许我只是担心没有和所有3个代码样本做同样的事情?
ProcessEventsAsync看起来像这样:
 async Task<InputResult> ProcessEventAsync(InputEvent ev) {...} 
	
 var inputs = events.Select(async ev => await ProcessEventAsync(ev)) .Select(t => t.Result) .Where(i => i != null) .ToList(); 
但是这对我来说似乎很奇怪,首先在select中使用asynchronous和等待。 根据Stephen Cleary的这个答案,我应该可以放弃这些。
 对Select的呼叫有效。 这两条线基本相同: 
 events.Select(async ev => await ProcessEventAsync(ev)) events.Select(ev => ProcessEventAsync(ev)) 
  (关于如何从ProcessEventAsync抛出同步exception,有一点小小的区别,但在这个代码的上下文中根本就没有关系。) 
然后select第二个select结果。 这是不是意味着这个任务不是asynchronous的,并且是同步执行的(这么多努力),或者这个任务是asynchronous执行的,而当它完成时,执行其余的查询。
这意味着查询被阻止。 所以它不是非同步的。
打破它:
 var inputs = events.Select(async ev => await ProcessEventAsync(ev)) 
将首先为每个事件启动一个asynchronous操作。 那么这一行:
  .Select(t => t.Result) 
将等待这些操作一次完成一个(首先等待第一个事件的操作,然后是下一个,然后是下一个等)。
 这是我不关心的部分,因为它会阻塞并且会在AggregateException包装任何exception。 
这是完全一样的吗?
 var tasks = await Task.WhenAll(events.Select(ev => ProcessEventAsync(ev))); var inputs = tasks.Where(result => result != null).ToList(); var inputs = (await Task.WhenAll(events.Select(ev => ProcessEventAsync(ev)))) .Where(result => result != null).ToList(); 
 是的,这两个例子是等价的。 它们都启动所有asynchronous操作( events.Select(...) ),然后asynchronous等待所有操作以任意顺序完成( await Task.WhenAll(...) ),然后继续执行其余的工作( Where... )。 
 这两个例子都不同于原来的代码。 原始代码被阻塞,并将在AggregateException包装exception。 
现有的代码正在工作,但阻止线程。
 .Select(async ev => await ProcessEventAsync(ev)) 
为每个事件创build一个新的任务,但是
 .Select(t => t.Result) 
阻止等待每个新任务的线程结束。
另一方面,你的代码产生相同的结果,但保持asynchronous。
只有一个评论你的第一个代码。 这条线
 var tasks = await Task.WhenAll(events... 
将产生一个单一的任务,所以variables应该以单数命名。
最后你的最后一个代码是相同的,但更简洁
供参考: Task.Wait / Task.WhenAll
使用Linq中现有的方法,看起来相当难看:
  var tasks = items.Select( async item => new { Item = item, IsValid = await IsValid(item) }); var tuples = await Task.WhenAll(tasks); var validItems = tuples .Where(p => p.IsValid) .Select(p => p.Item) .ToList(); 
希望以下版本的.NET将拿出更加优雅的工具来处理集合的任务和集合任务。