[英]async await: is the main thread suspended?
我正在閱讀有關async/await
關鍵字的內容,並且已閱讀:
當邏輯流到達 await 標記時,調用線程將掛起,直到調用完成。
好吧,我創建了一個簡單的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 是如何工作的呢?
問候
我讀過:當邏輯流到達等待標記時,調用線程將掛起,直到調用完成。
你從哪里讀到的那些廢話? 要么有一些您沒有引用的上下文,要么您應該停止閱讀包含此內容的任何文本。 await 的目的是做相反的事情。 await 的目的是讓當前線程在異步任務進行中時做有用的工作。
更新:我下載了你引用的書。 該部分中的所有內容絕對都是錯誤的。 扔掉這本書,買一本更好的書。
我不明白的是,當我單擊按鈕時,標簽 1 將顯示正在運行的文本,標簽將在 10 秒后顯示相同的文本,但在這 10 秒內,我能夠在文本框中輸入文本,所以看起來主線程正在運行......
沒錯。 這是發生的事情:
label1.Text = Thread.CurrentThread.ThreadState.ToString();
文本已設置。
button1.Text = await DoWork();
一堆事情在這里發生。 首先會發生什么? DoWork
被調用。 它有什么作用?
return Task.Run(() => { Thread.Sleep(10000);
它從線程池中取出一個線程,讓該線程休眠 10 秒,然后返回一個代表該線程正在完成的“工作”的任務。
現在我們回到這里:
button1.Text = await DoWork();
我們手頭有任務。 Await 首先檢查任務是否已經完成。 不是。 接下來,它將此方法的其余部分注冊為任務的繼續。 然后它返回給它的調用者。
嘿,它的調用者是什么? 反正我們是怎么到這里的?
一些代碼調用了這個事件處理程序; 它是處理 Windows 消息的事件循環。 它看到一個按鈕被點擊並分派給剛剛返回的點擊處理程序。
現在會發生什么? 事件循環繼續運行。 正如您所注意到的,您的 UI 一直運行良好。 最終該線程會滴答十秒,任務的繼續被激活。 那有什么作用?
這會在 Windows 隊列中發布一條消息,說“您現在需要運行該事件處理程序的其余部分;我得到了您正在尋找的結果。”
主線程事件循環最終會得到該消息。 所以事件處理程序從它停止的地方開始:
button1.Text = await DoWork();
await 現在從任務中提取結果,將其存儲在按鈕文本中,然后返回到事件循環。
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
的返回值改成Task
看是否完成)。
除了上述轉換之外,系統還智能判斷Task
是否在 UI 線程上啟動並再次編組回 UI 線程以確保一切按預期進行。 這可能是您沒有意識到的主要事情,但在狀態機方面的擴展有時會解釋asyc
/ await
真正含義(而不是讓它變得神秘)。
通過編寫await
,您是在說 - 此時請停止執行該方法,等待DoWork
完成,然后再繼續。
與異步並等待(C#),異步編程在異步方法部分會發生什么有一個一步一步的解釋,與圖片的在發生什么, async
方法。
更好的解釋是await (C# 參考) 。 看看下面對WaitSynchronously
和WaitAsynchronouslyAsync
評論。
該文章還指出(強調我的):
await 運算符應用於異步方法中的任務,以暫停該方法的執行,直到等待的任務完成。 任務代表正在進行的工作。
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";
}
基本上,關鍵是程序執行以同步方式繼續,直到或除非遇到 await。 一旦遇到 await,假設對於任務 A,編譯器將切換回調用此異步方法的 main 方法,而無需使用 await 關鍵字,並將繼續從任務 A 的調用點執行程序,因為編譯器知道它必須等待完成任務 A 那么為什么不完成它的其他待處理任務。
這里發生的事情是 main 方法中不等待 button1_Click 事件,因此一旦遇到 await DoWork() 它將繼續執行。 DoWork() 完成后,編譯器將繼續執行 button1_Click 中的進一步代碼
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.