我正在试验 async-await 并且我遇到了这种相当奇怪的行为,至少对我来说是这样。
我创建了三种模拟长时间运行任务的方法。
考虑两个按钮单击处理程序:
对于 button1_click,经过的时间约为 6000 毫秒,而 button2_click 约为 3000 毫秒。
我无法理解为什么会发生这种情况,即 6000 毫秒与 3000 毫秒。
private async Task<string> TaskOne()
{
await Task.Delay(1000);
return "task one";
}
private async Task<string> TaskTwo()
{
await Task.Delay(2000);
return "task two";
}
private async Task<string> TaskThree()
{
await Task.Delay(3000);
return "task three";
}
//time elapsed = 6000+ms
private async void button1_Click(object sender, EventArgs e)
{
var watch = new Stopwatch();
watch.Start();
await TaskOne();
await TaskTwo();
await TaskThree();
watch.Stop();
textBox3.Text = watch.ElapsedMilliseconds.ToString();
}
//time elapsed = 3000+ms
private async void button2_Click(object sender, EventArgs e)
{
var watch = new Stopwatch();
watch.Start();
var taskOne = TaskOne();
var taskTwo = TaskTwo();
var taskThree = TaskThree();
await taskOne;
await taskTwo;
await taskThree;
watch.Stop();
textBox3.Text = watch.ElapsedMilliseconds.ToString();
}
Run Code Online (Sandbox Code Playgroud)
小智 7
在这种情况下:
await TaskOne();
await TaskTwo();
await TaskThree();
Run Code Online (Sandbox Code Playgroud)
TaskTwo() 在 TaskOne() 完成之前无法启动,因为您正在等待它。同样,由于等待,TaskThree() 在 TaskTwo() 完成之前无法启动。
下一个:
var taskOne = TaskOne();
var taskTwo = TaskTwo();
var taskThree = TaskThree();
await taskOne;
await taskTwo;
await taskThree;
Run Code Online (Sandbox Code Playgroud)
您同时开始所有 3 个任务,然后等待它们。所以这就是为什么它只需要与运行时间最长的任务一样长的时间。你会惊讶于有多少人不了解异步等待。如果任务不相互依赖,那么这就是要走的路。
这里的要点(否则这是一个非常常见的误解),await实际上确实意味着“等待”。
强调我的
await 运算符暂停对封闭异步方法的计算,直到其操作数表示的异步操作完成。当异步操作完成时,await 运算符返回操作的结果(如果有)。
当 await 运算符应用于表示已完成操作的操作数时,它会立即返回操作结果,而不会暂停封闭方法。
await 运算符不会阻塞评估异步方法的线程。当 await 运算符挂起封闭的异步方法时,控制权返回给方法的调用者。
所以这就是正在发生的事情。在您的第一个示例中,您正在启动每个任务并等待它们连续完成。也就是说,这就像要求某人去做某事并完成,然后再要求下一个人做某事,等等
await TaskOne(); // start, do something and wait for it
await TaskTwo(); // start, do something and wait for it
await TaskThree(); // start, do something and wait for it
Run Code Online (Sandbox Code Playgroud)
你的第二个例子。您实际上是在启动 3 个任务(热),然后等待它们一次完成一个。也就是说它们同时运行,并按顺序等待。
也就是说,你要对 3 个朋友说,去做些事情,然后等第一个回来,然后是第二个,然后是第三个。它更有效率......在前一个回来之前,没有讨厌的朋友闲逛。
即使第二个任务在第一个任务之前完成,在查看第二个任务的完成状态等之前,您实际上仍然在等待第一个任务。
var taskOne = TaskOne(); // start, do something
var taskTwo = TaskTwo(); // start, do something
var taskThree = TaskThree(); // start, do something
// all 3 tasks are started
await taskOne; // wait for it
await taskTwo; // wait for it
await taskThree; // wait for it
Run Code Online (Sandbox Code Playgroud)
或者类似地你可以使用 Task.WhenAll
创建一个将在所有提供的任务完成后完成的任务。
var taskOne = TaskOne(); // start, do something
var taskTwo = TaskTwo(); // start, do something
var taskThree = TaskThree(); // start, do something
// wait for them all to finish!
await Task.WhenAll(taskOne, taskTwo, taskThree);
Run Code Online (Sandbox Code Playgroud)