假设我有以下代码:public async void Run(){ TaskCompletionSource t = new TaskCompletionSource(); Prepare(t.Task); await Task.Delay(1000); t.SetResult(); Console.
假设我有这样的代码:
public async void Run()
{
TaskCompletionSource t = new TaskCompletionSource();
Prepare(t.Task);
await Task.Delay(1000);
t.SetResult();
Console.WriteLine("End");
}
public async void Prepare(Task task)
{
await Run(task, "A");
await Run(task, "B");
await Run(task, "C");
await Run(task, "D");
}
public async Task Run(Task requisite, string text)
{
await requisite;
Console.WriteLine(text);
}
时会发生什么 t.SetResult();
?这是多线程吗?控制台中项目的顺序有任何保证吗?如果我有一个 List<>
,并且该 Run
方法会改变它,我需要担心多线程吗?
这在很大程度上取决于应用程序处理的吞吐量 - 如果流量很大,则可能涉及多个线程。
但一般来说, Task
使用 async
/ await
并不保证多线程,当需要时才会使用新线程(来自线程池) - 当前线程正忙于某些工作并且无法承担新的工作。
异步执行的想法是,当有工作需要等待时(我们的处理器必须等待某些事情,比如 I/O 操作),它会释放当前线程并让其执行其他工作。
这样,一个线程可能正在“并行”执行两个任务。但这是多任务,而不是多线程。
有了这些知识,让我们来分析您的代码。
首先,您创建 TaskCompleti完成Source
具有 Task
“正在进行”并且可以等待的 - 但是一旦我们调用它,它就会 SetResult
on TaskCompletionSource
.
然后我们调用 Prepare
,我们并不等待,但它等待传递的 Task
,因此此执行路径将停止 await Run(task, "A")
并等待任务完成,这将在我们调用时发生 SetResult
(如前所述)。之后 Prepare
(因此任务已经在等待中),我们调用 await Task.Delay
- 我们这里还有另一个 await
,这次是为了延迟。由于我们使用 Task
s ,因此不会创建新线程,因为 await Run
只是等待,线程可以继续进行其他工作并将处理代码的执行。因此,等待延迟和等待任务将并行、异步完成。
然后,当延迟完成时,它将设置任务的结果,这意味着 await Run(task, "A")
将获得\'解除阻塞\',打印结果并继续 await Run(task, "B")
,但这将尝试等待已经完成的任务,因此它将同步执行(任务已经完成,没有什么可等待的),立即打印\'B\',然后\'C\',然后\'D\'(按顺序)。
您可能会遇到一个问题 - 您的程序可能会在 Prepare
方法中的所有任务完成之前完成 - 因为它是 async void
,我们无法等待它。我建议进行一些小改进:
public async void Run()
{
TaskCompletionSource t = new TaskCompletionSource();
var prepareTask = Prepare(t.Task);
await Task.Delay(1000);
t.SetResult();
await prepareTask;
Console.WriteLine("End");
}
public async Task Prepare(Task task)
{
await Run(task, "A");
await Run(task, "B");
await Run(task, "C");
await Run(task, "D");
}
public async Task Run(Task requisite, string text)
{
await requisite;
Console.WriteLine(text);
}