让我们考虑一下这段代码:
var tasks = actionItems.Select(t => DoSmthAsync());
var resultAll = await Task.WhenAll(tasks);
及方法:
public async Task<int> DoSmthAsync()
{
Debug.WriteLine("Threadid=" + Thread.CurrentThread.ManagedThreadId);
var result = await DoSmthAnotherAsync();
Debug.WriteLine("ThreadId=" + Thread.CurrentThread.ManagedThreadId);
return result;
}
我希望这将在不同的线程中并行执行,但我看到它在同一个线程中工作。另外,我不明白任务何时运行?
您将
async await
模型与并行编程混淆了。
Select
将连续迭代你的 actionItems
。当您等待 DoSmthAsync
时,Select
会将控制权返回给调用者(在本例中为 DoSmthAnotherAsync
迭代器),因此您将获得在一个线程上创建的 Task<int>
列表。
要并行运行
Select
语句,您需要使用 PLINQ。
var tasks = actionItems.AsParallel().Select(t => DoSmthAsync());
这将产生您预期的结果。
然后您需要
await Task.WhenAll(tasks);
等待任务结果。然后,您可以访问 Task<int>
列表中每个 tasks
的结果及其各自的 Result
属性。
我希望这将在不同的线程中并行执行。
这在Victor Wilson的回答中进行了解释,所以我将重点解释这一点:
另外,我不明白任务何时运行?
A
Task
通常在创建时启动(在这种情况下,它称为 hot 任务)。异步方法和所有内置 .NET API 都会返回热门任务。可以使用 Task
构造函数(创建所谓的 cold 任务)创建未启动的
Task
,但这些任务通常由创建它们的同一个库在内部启动。向外部世界暴露一个冷酷的任务,结束期望调用者Start
它,是我从未见过的事情,如果存在的话,那将是非常令人惊讶的(以一种不愉快的方式)。
此构造函数仅适用于需要将任务的创建和启动分开的高级场景。
var tasks = actionItems.Select(t => DoSmthAsync());
Select
LINQ 方法返回一个延迟可枚举序列,而不是物化集合。当您调用方法Task.WhenAll(tasks)
时,任务的实际实现就会发生。