LINQ代码中的异步 - 澄清?

Roy*_*mir 10 .net c# asynchronous task-parallel-library async-await

几乎每个SO关于这个主题的答案都表明:

LINQ与async无法完美配合

另外:

我建议您不要将其视为"在LINQ中使用异步"

但在斯蒂芬的书中有一个样本:

问题:您有一组要处理的任务,并且您希望在完成后对每个任务执行一些处理.但是,您希望在完成后立即对每个进行处理,而不是等待任何其他任务.

推荐的解决方案之一是:

static async Task<int> DelayAndReturnAsync(int val)
{
 await Task.Delay(TimeSpan.FromSeconds(val));
 return val;
}

// This method now prints "1", "2", and "3".
static async Task ProcessTasksAsync()
{
 // Create a sequence of tasks.
 Task<int> taskA = DelayAndReturnAsync(2);
 Task<int> taskB = DelayAndReturnAsync(3);
 Task<int> taskC = DelayAndReturnAsync(1);
 var tasks = new[] { taskA, taskB, taskC };
 var processingTasks = tasks.Select(async t =>
    {
    var result = await t;
    Trace.WriteLine(result);
    }).ToArray();

// Await all processing to complete
await Task.WhenAll(processingTasks);

}
Run Code Online (Sandbox Code Playgroud)

问题#1:

我不明白为什么现在async在LINQ语句中 - 确实有效.我们不是只说" 考虑async在LINQ中使用"吗?

问题2:

当控制到达await t这里时 - 实际发生了什么?控件是否离开了ProcessTasksAsync方法?或者它是否保留匿名方法并继续迭代?

Yuv*_*kov 9

我不明白为什么现在在LINQ语句中异步 - 确实有效.我们不是只说"不考虑在LINQ中使用异步"吗?

async 大多数情况下不能与LINQ一起使用,因为IEnumerable<T>扩展并不总是正确推断委托类型并且遵从Action<T>.他们对Task班级没有特别的了解.这意味着实际的异步委托变得async void很糟糕.在这种情况下Enumerable.Select,我们有一个重载,它返回一个Func<T>(Func<Task>在我们的情况下也是如此),这相当于async Task,因此它适用于异步用例.

控制到达等待时间 - 实际发生了什么?控件是否保留ProcessTasksAsync方法?

不,它没有.Enumerable.Select是关于预测序列中的所有元素.这意味着对于集合中的每个元素,await t它将控制权返回迭代器,迭代器将继续迭代所有元素.这就是为什么你以后必须await Task.WhenAll确保所有元素都已完成执行的原因.