[英]How Async and Await works
我试图了解 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 已经完成执行并且结果可用。 当到达 await 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;
一样结束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);
}
几个重要的注意事项:
Task
。 它使用任务的GetAwaiter()
方法及其 API,或任何其他具有此方法或扩展方法的类。MyMethod
被拆分,等待MyMethod
人如何知道所有部分何时完成? 当您的 async 方法返回Task
,编译器会生成一个特殊的Task
,它使用状态机跟踪所有内容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.