Async和Await的工作原理
本文关键字:工作 Await Async | 更新日期: 2023-09-27 17:49:36
我正在努力了解Async和Await是如何工作的。如何在程序中控制行程。这是我试图理解的代码。
public async Task MyMethod()
{
Task<int> longRunningTask = LongRunningOperation();
//indeed you can do independent to the int result work here
MySynchronousMethod();
//and now we call await on the task
int result = await longRunningTask;
//use the result
Console.WriteLine(result);
}
public async Task<int> LongRunningOperation() // assume we return an int from this long running operation
{
await Task.Delay(5000); //5 seconds delay
return 1;
}
private void Button_Click_3(object sender, RoutedEventArgs e)
{
MyMethod();
}
单击按钮时,将调用MyMethod()
,并从MyMethod调用LongRunningOperation()
,这需要5秒才能完成。所以我的问题是
这条线是什么意思
任务longRunningTask=LongRunningOperation((;
int result = await longRunningTask;
是什么
上述线路可以提交,我们可以像一样构建一条线路
Task<int> longRunningTask = await LongRunningOperation();
或
int result = await longRunningTask;
请有人向我解释一下我不清楚的上述代码
1( 如果longRunningOperation尚未完成并且仍在运行,MyMethod((将返回其调用方法,因此主线程不会被阻塞。当longRunningOperation完成时,ThreadPool中的一个线程(可以是任何线程(将返回到MyMethod((的前一状态并继续执行(在本例中,将结果打印到控制台(。
第二种情况是longRunningOperation已经完成执行,并且结果可用。当到达wait-longRunningOperation时,编译器知道它有结果,并将继续在同一个线程上执行代码。(在这种情况下,将结果打印到控制台(。
第1点对我来说根本不清楚,就像的"if the longRunningOperation hasn't finished and is still running, MyMethod() will return to its calling method
"语句一样
如果可能的话,请更详细地解释这一点。感谢
//this is pseudocode
async Method()
{
code;
code;
await something;
moreCode;
}
当调用Method
时,它执行其内容(code;
行(,直到await something;
。在这一点上,something;
被激发,方法结束时就像return;
一样。
something;
执行它需要的操作,然后返回。
当something;
返回时,执行返回到Method
并从await
继续,执行moreCode;
以一种更为示意的方式,以下是发生的情况:
- 方法被调用
- 执行
code;
- 执行
something;
,流程返回到调用Method
的点 - 执行继续进行
Method
调用之后的内容 - 当
something;
返回时,流在Method
内部返回 - 执行
moreCode;
,Method
本身结束(是的,可能还有其他await
,依此类推(
我的博客上有一篇async
简介,你可能会觉得很有帮助。
此代码:
int result = await LongRunningOperation();
本质上与此代码相同:
Task<int> resultTask = LongRunningOperation();
int result = await resultTask;
所以,是的,LongRunningOperation
是由该方法直接调用的。
当await
运算符被传递一个已经完成的任务时,它将提取结果并继续执行该方法(同步(。
当await
运算符被传递一个不完整的任务(例如,LongRunningOperation
返回的任务将不完整(时,默认情况下,await
将捕获当前上下文并从该方法返回一个不完成的任务。
稍后,当await
任务完成时,该方法的其余部分被安排在该上下文中运行。
这个"上下文"是SynchronizationContext.Current
,除非它是null
,在这种情况下它是TaskScheduler.Current
。如果你在控制台应用程序中运行这个,那么上下文通常是线程池上下文,所以async
方法将在线程池线程上继续执行。但是,如果在UI线程上执行相同的方法,那么上下文就是UI上下文,async
方法将在UI线程中继续执行。
幕后C#编译器实际上将代码转换为状态机。它生成了更多的代码,这样每当等待任务或异步操作完成时,它都会在幕后从停止的地方继续执行。就你的问题而言,每次异步操作完成后,当你最初开始调用异步方法时,异步方法都会在调用线程上被回调。例如,它将在你启动的线程上执行你的代码。因此,异步操作将在Task
线程上运行,然后结果将返回到你最初调用方法的线程上并继续执行。
Await
将从Task
或异步操作中获取值,并在返回执行时将其从任务中"取消装箱"。在这种情况下,它会自动将其放入int值中,因此无需存储Task<int>
。
您的代码在LongRunningTask()
上有等待的问题,您很可能只想返回不带async
的长任务方法,然后让MyMethod
执行等待。
int value = await LongWaitingTask()
异步等待和生成的状态机
返回Task
或void
是async
方法的要求。
可以更改它,这样当您从执行异步任务返回时,它将在使用Task.ConfigureAwait
方法执行异步任务的线程上执行剩余代码。
这样想可能更容易:每当您有一个await
时,编译器就会将您的方法拆分为2部分:一部分在await
之前,另一部分在它之后。第二部分在第一部分成功完成后运行。
在您的代码中,第一种方法看起来大致相当于以下内容:
public async Task MyMethod()
{
Task<int> longRunningTask = LongRunningOperation();
MySynchronousMethod();
longRunningTask.ContinueWith(t => part2(t.Result));
}
void part2(int result)
{
Console.WriteLine(result);
}
几个重要注意事项:
- 它显然比这个复杂得多,因为它应该支持试试catch和其他。此外,它并没有真正使用任务
- CCD_ 49实际上并没有被直接使用。它使用任务的
GetAwaiter()
方法及其API,或使用此方法或扩展方法的任何其他类 - 如果一个方法中有多个等待,它将被多次拆分
- 如果
MyMethod
被拆分,等待MyMethod
的人如何知道所有部分何时完成?当异步方法返回一个Task
时,编译器会生成一个特殊的Task
,它会用状态机跟踪所有内容