几乎每个SO关于这个主题的答案都说明了:
另外:
I recommend that you not think of this as "using async within 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);
}
问题#1:
我不明白为什么现在async
在LINQ语句中 - 确实有效。我们不是只是说“不考虑在LINQ中使用async
吗?”
问题#2:
当控件到达await t
时 - 实际发生了什么?控件是否离开ProcessTasksAsync
方法?或者它是否保留匿名方法并继续迭代?
答案 0 :(得分:8)
我不明白为什么现在在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
,以确保所有元素都已完成执行。
答案 1 :(得分:3)
问题1:
不同之处在于每项任务都是继续,并进行了额外的处理:Trace.WriteLine(result);
。在您指向的链接中,该代码不会更改任何内容,只会产生等待和包装其他任务的开销。
问题2:
当控件到达等待时间 - 实际发生了什么?
等待ProcessTasksAsync
任务的结果,然后继续Trace.WriteLine(result);
。我们可以说当我们得到结果时控件会离开ProcessTasksAsync
方法,并且处理仍然在匿名方法中。
最后,我们有await Task.WhenAll(processingTasks);
等待所有任务,包括在继续之前完成的额外处理(Trace.WriteLine(result);
),但每个任务都没有等待其他任务继续执行:Trace.WriteLine(result);
答案 2 :(得分:0)
这样会更好:
static async Task<int> DelayAndReturnAsync(int val)
{
await Task.Delay(TimeSpan.FromSeconds(val));
return val;
}
static async Task AwaitAndProcessAsync(Task<int> task)
{
var result = await task;
Console.WriteLine(result);
}
// 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(AwaitAndProcessAsync).ToArray();
// Await all processing to complete
await Task.WhenAll(processingTasks);
}
任务数组,因为AwaitAndProcessAsync返回任务。