async await:主线程是否挂起?
async await: is the main thread suspended?
我正在阅读有关 async/await
关键字的内容,我已经阅读了:
When the flow of logic reaches the await token, the calling thread is
suspended until the call completes.
好吧,我创建了一个简单的 windows forms application
,放置了两个标签、一个按钮和一个文本框,然后我编写了代码:
private async void button1_Click(object sender, EventArgs e)
{
label1.Text = Thread.CurrentThread.ThreadState.ToString();
button1.Text = await DoWork();
label2.Text = Thread.CurrentThread.ThreadState.ToString();
}
private Task<string> DoWork()
{
return Task.Run(() => {
Thread.Sleep(10000);
return "done with work";
});
}
我不明白的是,当我点击按钮时,label1 将具有文本 Running
并且标签将在 10 秒后具有相同的文本,但是在这 10 秒内我是能够在我的文本框中输入文本,所以主线程似乎是 运行...
那么,async/await 是如何工作的?
这是书中的 "screenshot":
此致
async
/await
创建一个状态机来为您处理延续。一个非常粗略的等价物(没有一堆特征)是一个显式的延续方法,例如:
private void button1_Click_Continuation(string value)
{
button1.Text = value;
label2.Text = Thread.CurrentThread.ThreadState.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
label1.Text = Thread.CurrentThread.ThreadState.ToString();
DoWork(button1_Click_Continuation);
}
private void DoWork(Action<string> continuation)
{
Task.Run(() => {
Thread.Sleep(10000);
continuation("done with work");
});
}
请注意,我仍在单独的线程上使用 Task.Run
到 运行。请注意,此版本无法跟踪进度(而原始版本可以将 button1_Click
的 return 值更改为 Task
以查看它是否已完成)。
除了上述转换之外,系统还会智能判断 Task
是否在 UI 线程上启动并再次编组回 UI 线程以确保一切正常预计。这可能是您没有意识到的主要事情,但在状态机方面的扩展有时会解释 asyc
/await
的真正含义(而不是让它变得神秘)。
通过写 await
,您是在说 - 请在此时停止执行该方法,等待 DoWork
完成,然后再继续。
Asynchronous Programming with async and await (C#) 在 异步方法中发生的事情 部分有一步一步的解释,并附有图片,说明 async
方法中发生的事情.
更好的解释在 await (C# reference)。查看下面 WaitSynchronously
和 WaitAsynchronouslyAsync
的评论。
文章还指出(强调我的):
The await operator is applied to a task in an asynchronous method to suspend the execution of the method until the awaited task completes. The task represents ongoing work.
private async void button1_Click(object sender, EventArgs e)
{
// Call the method that runs asynchronously.
string result = await WaitAsynchronouslyAsync();
// Call the method that runs synchronously.
//string result = await WaitSynchronously ();
// Display the result.
textBox1.Text += result;
}
// The following method runs asynchronously. The UI thread is not
// blocked during the delay. You can move or resize the Form1 window
// while Task.Delay is running.
public async Task<string> WaitAsynchronouslyAsync()
{
await Task.Delay(10000);
return "Finished";
}
// The following method runs synchronously, despite the use of async.
// You cannot move or resize the Form1 window while Thread.Sleep
// is running because the UI thread is blocked.
public async Task<string> WaitSynchronously()
{
// Add a using directive for System.Threading.
Thread.Sleep(10000);
return "Finished";
}
I've read that: When the flow of logic reaches the await token, the calling thread is suspended until the call completes.
你是从哪里读到这些废话的?要么那里有一些你没有引用的上下文,要么你应该停止阅读包含它的任何文本。 await 的目的是做相反的事情。 await 的要点是在异步任务运行时保持当前线程做有用的工作。
更新:我下载了您提到的那本书。该部分中的所有内容绝对是错误的。把这本书扔掉,买一本更好的书。
What I don't understand is that when I click the button, the label1 will have the text Running and the label will have the same text only after 10 seconds, but in these 10 seconds I was able to enter the text in my textbox, so it seems that the main thread is running...
没错。事情是这样的:
label1.Text = Thread.CurrentThread.ThreadState.ToString();
文本已设置。
button1.Text = await DoWork();
这里发生了很多事情。首先会发生什么? DoWork
被调用。它有什么作用?
return Task.Run(() => { Thread.Sleep(10000);
它从线程池中抓取一个线程,让该线程休眠十秒钟,然后 returns 代表该线程正在完成的 "work" 任务。
现在我们回到这里:
button1.Text = await DoWork();
我们手头有任务。 Await 首先检查任务是否已经完成。它不是。接下来它将此方法的其余部分注册为任务的 continuation。然后它 returns 给它的调用者。
嘿,它的调用者是什么?我们是怎么到这里的?
一些代码调用了这个事件处理程序;事件循环正在处理 Windows 消息。它看到一个按钮被点击并被分派给刚刚返回的点击处理程序。
现在发生了什么?事件循环保持运行。正如您所注意到的,您的 UI 保持 运行 很好。最终该线程结束 10 秒,任务的继续被激活。那有什么作用?
向 Windows 队列发送消息说 "you need to run the rest of that event handler now; I have the result you were looking for."
主线程事件循环最终到达该消息。所以事件处理程序从它停止的地方开始:
button1.Text = await DoWork();
await 现在从任务中提取结果,将其存储在按钮文本中,然后 returns 返回事件循环。
基本上,关键是程序以同步方式继续执行,直到或除非遇到 await。一旦遇到 await,假设对于任务 A,编译器将切换回调用此异步方法的 main 方法 不带 await 关键字 并将继续从任务调用点执行程序A 因为编译器知道它必须等待任务 A 完成,所以为什么不完成它的其他未决任务。
这里发生的事情是 button1_Click main 方法中没有等待事件,因此一旦遇到 await DoWork() 它将继续执行。在 DoWork() 完成后,编译器将继续执行 button1_Click
中的进一步代码
我正在阅读有关 async/await
关键字的内容,我已经阅读了:
When the flow of logic reaches the await token, the calling thread is suspended until the call completes.
好吧,我创建了一个简单的 windows forms application
,放置了两个标签、一个按钮和一个文本框,然后我编写了代码:
private async void button1_Click(object sender, EventArgs e)
{
label1.Text = Thread.CurrentThread.ThreadState.ToString();
button1.Text = await DoWork();
label2.Text = Thread.CurrentThread.ThreadState.ToString();
}
private Task<string> DoWork()
{
return Task.Run(() => {
Thread.Sleep(10000);
return "done with work";
});
}
我不明白的是,当我点击按钮时,label1 将具有文本 Running
并且标签将在 10 秒后具有相同的文本,但是在这 10 秒内我是能够在我的文本框中输入文本,所以主线程似乎是 运行...
那么,async/await 是如何工作的?
这是书中的 "screenshot":
此致
async
/await
创建一个状态机来为您处理延续。一个非常粗略的等价物(没有一堆特征)是一个显式的延续方法,例如:
private void button1_Click_Continuation(string value)
{
button1.Text = value;
label2.Text = Thread.CurrentThread.ThreadState.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
label1.Text = Thread.CurrentThread.ThreadState.ToString();
DoWork(button1_Click_Continuation);
}
private void DoWork(Action<string> continuation)
{
Task.Run(() => {
Thread.Sleep(10000);
continuation("done with work");
});
}
请注意,我仍在单独的线程上使用 Task.Run
到 运行。请注意,此版本无法跟踪进度(而原始版本可以将 button1_Click
的 return 值更改为 Task
以查看它是否已完成)。
除了上述转换之外,系统还会智能判断 Task
是否在 UI 线程上启动并再次编组回 UI 线程以确保一切正常预计。这可能是您没有意识到的主要事情,但在状态机方面的扩展有时会解释 asyc
/await
的真正含义(而不是让它变得神秘)。
通过写 await
,您是在说 - 请在此时停止执行该方法,等待 DoWork
完成,然后再继续。
Asynchronous Programming with async and await (C#) 在 异步方法中发生的事情 部分有一步一步的解释,并附有图片,说明 async
方法中发生的事情.
更好的解释在 await (C# reference)。查看下面 WaitSynchronously
和 WaitAsynchronouslyAsync
的评论。
文章还指出(强调我的):
The await operator is applied to a task in an asynchronous method to suspend the execution of the method until the awaited task completes. The task represents ongoing work.
private async void button1_Click(object sender, EventArgs e)
{
// Call the method that runs asynchronously.
string result = await WaitAsynchronouslyAsync();
// Call the method that runs synchronously.
//string result = await WaitSynchronously ();
// Display the result.
textBox1.Text += result;
}
// The following method runs asynchronously. The UI thread is not
// blocked during the delay. You can move or resize the Form1 window
// while Task.Delay is running.
public async Task<string> WaitAsynchronouslyAsync()
{
await Task.Delay(10000);
return "Finished";
}
// The following method runs synchronously, despite the use of async.
// You cannot move or resize the Form1 window while Thread.Sleep
// is running because the UI thread is blocked.
public async Task<string> WaitSynchronously()
{
// Add a using directive for System.Threading.
Thread.Sleep(10000);
return "Finished";
}
I've read that: When the flow of logic reaches the await token, the calling thread is suspended until the call completes.
你是从哪里读到这些废话的?要么那里有一些你没有引用的上下文,要么你应该停止阅读包含它的任何文本。 await 的目的是做相反的事情。 await 的要点是在异步任务运行时保持当前线程做有用的工作。
更新:我下载了您提到的那本书。该部分中的所有内容绝对是错误的。把这本书扔掉,买一本更好的书。
What I don't understand is that when I click the button, the label1 will have the text Running and the label will have the same text only after 10 seconds, but in these 10 seconds I was able to enter the text in my textbox, so it seems that the main thread is running...
没错。事情是这样的:
label1.Text = Thread.CurrentThread.ThreadState.ToString();
文本已设置。
button1.Text = await DoWork();
这里发生了很多事情。首先会发生什么? DoWork
被调用。它有什么作用?
return Task.Run(() => { Thread.Sleep(10000);
它从线程池中抓取一个线程,让该线程休眠十秒钟,然后 returns 代表该线程正在完成的 "work" 任务。
现在我们回到这里:
button1.Text = await DoWork();
我们手头有任务。 Await 首先检查任务是否已经完成。它不是。接下来它将此方法的其余部分注册为任务的 continuation。然后它 returns 给它的调用者。
嘿,它的调用者是什么?我们是怎么到这里的?
一些代码调用了这个事件处理程序;事件循环正在处理 Windows 消息。它看到一个按钮被点击并被分派给刚刚返回的点击处理程序。
现在发生了什么?事件循环保持运行。正如您所注意到的,您的 UI 保持 运行 很好。最终该线程结束 10 秒,任务的继续被激活。那有什么作用?
向 Windows 队列发送消息说 "you need to run the rest of that event handler now; I have the result you were looking for."
主线程事件循环最终到达该消息。所以事件处理程序从它停止的地方开始:
button1.Text = await DoWork();
await 现在从任务中提取结果,将其存储在按钮文本中,然后 returns 返回事件循环。
基本上,关键是程序以同步方式继续执行,直到或除非遇到 await。一旦遇到 await,假设对于任务 A,编译器将切换回调用此异步方法的 main 方法 不带 await 关键字 并将继续从任务调用点执行程序A 因为编译器知道它必须等待任务 A 完成,所以为什么不完成它的其他未决任务。
这里发生的事情是 button1_Click main 方法中没有等待事件,因此一旦遇到 await DoWork() 它将继续执行。在 DoWork() 完成后,编译器将继续执行 button1_Click
中的进一步代码