我试图了解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已经完成执行并且结果可用。当到达等待longRunningOperation时,编译器知道它有结果并将继续在同一个线程上执行代码。 (在这种情况下打印结果到控制台)。
第1点对我来说并不清楚,就像#34; if the longRunningOperation hasn't finished and is still running, MyMethod() will return to its calling method
&#34;
如果可能的话,更详细地解释第一点。感谢
答案 0 :(得分:24)
我已经按照以下方式接受了教育,我发现这是一个非常明确和简洁的解释:
//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
- 依赖于此类似等等)答案 1 :(得分:22)
我的博客上有async
intro,您可能会觉得有帮助。
此代码:
int result = await LongRunningOperation();
与此代码基本相同:
Task<int> resultTask = LongRunningOperation();
int result = await resultTask;
所以,是的,LongRunningOperation
由该方法直接调用。
当await
运算符传递已完成的任务时,它将提取结果并继续执行该方法(同步)。
当await
运算符被传递一个不完整的任务(例如,LongRunningOperation
返回的任务将不完整)时,默认情况下await
将捕获当前上下文并返回方法不完整的任务。
稍后,当await
任务完成时,该方法的其余部分将安排在该上下文中运行。
这&#34; context&#34;是SynchronizationContext.Current
,除非它是null
,在这种情况下它是TaskScheduler.Current
。如果您在Console应用程序中运行此操作,则上下文通常是线程池上下文,因此async
方法将在线程池线程上继续执行。但是,如果在UI线程上执行相同的方法,则上下文是UI上下文,async
方法将在UI线程上继续执行。
答案 2 :(得分:7)
幕后花絮C#编译器实际上将您的代码转换为状态机。它会生成更多代码,以便在每次等待任务或异步操作完成后在幕后,它将从中断处继续执行。就您的问题而言,每次异步操作完成时,当您最初启动对异步方法的调用时,将在调用线程上回调异步方法。例如,它将在您开始的线程上执行您的代码。因此异步操作将在Task线程上运行,然后结果将返回到最初调用该方法的线程并继续执行。
await将从Task或async操作中获取值,并在返回执行时从任务中“取消装箱”。在这种情况下,它会自动将其放入int值,因此无需存储任务。 / p>
你的代码有问题,它等待在LongRunningTask()上,你很可能只想在没有异步的情况下返回长任务方法,然后让你的MyMethod执行await。
int value = await LongWaitingTask()
http://www.codeproject.com/Articles/535635/Async-Await-and-the-Generated-StateMachine
异步方法的要求是返回Task或void。
可以更改它,以便当您从执行异步任务返回时,它将执行线程上的剩余代码,使用http://msdn.microsoft.com/en-us/library/system.threading.tasks.task.configureawait(v=vs.110).aspx执行异步任务
答案 3 :(得分:0)
这样思考可能会更容易:
只要有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);
}
之后的另一部分。
第二部分在第一个部分成功完成之后运行。
在您的代码中,第一个方法看起来大致与此等效:
Task
一些重要说明:
GetAwaiter()
实际上并未直接使用。它使用任务的MyMethod
方法及其API,或任何其他具有此方法或扩展方法的类。MyMethod
被拆分,等待Task
的人怎么知道什么时候完成?当您的异步方法返回Task
时,编译器会生成一个特殊的.container-div
,它会使用状态机跟踪所有内容。