非同步 - 留在目前執行緒上?
我讀過 Eric lippert 的文章,關於
async, 以及人們對async關鍵字的困惑。他說 :it(
async) 表示“此方法包含涉及等待非同步操作的控制流,因此將由編譯器重寫為繼續傳遞樣式,以確保非同步操作可以在正確的位置恢復此方法。” 非同步方法的全部意義在於您盡可能多地停留在目前執行緒上我不明白這一點。如果我執行一個非同步方法 (
Task) 並且它執行,它肯定會在另一個執行緒上執行。此外,如果我編寫一個方法使用
await,(恕我直言)它會釋放正常的控制流,並且程式碼會在稍後在另一個執行緒上以 類似的方式“重構”。ContinueWith我用 (console) 測試了它:
/*1*/ public void StartChain() /*2*/ { /*3*/ var a = FuncA(); /*4*/ Console.WriteLine(a.Result); /*5*/ } /*6*/ /*7*/ public async Task < int > FuncA() /*8*/ { /*9*/ Console.WriteLine("A--" + Thread.CurrentThread.ManagedThreadId); /*10*/ var t = await FuncB(); /*11*/ Console.WriteLine("B--" + Thread.CurrentThread.ManagedThreadId); /*12*/ return t; /*13*/ } /*14*/ /*15*/ public async Task < int > FuncB() /*16*/ { /*17*/ Console.WriteLine("C--" + Thread.CurrentThread.ManagedThreadId); /*18*/ await Task.Delay(2000); /*19*/ Console.WriteLine("D--" + Thread.CurrentThread.ManagedThreadId); /*20*/ return 999; /*21*/ } /*22*/ /*23*/ void Main() /*24*/ { /*25*/ StartChain(); /*26*/ } /*27*/結果是:
A--7 C--7 D--17 <-----D and B are on different thread B--17 999那麼 Eric 所說的“留在目前執行緒上”是什麼意思?
編輯1:
其中
asp.net還返回不同的執行緒 ID。public async Task<int> FuncA() { Response.Write("<br/>C----" + Thread.CurrentThread.ManagedThreadId); var t = await FuncB(); Response.Write("<br/>D----" + Thread.CurrentThread.ManagedThreadId); return t; } public async Task<int> FuncB() { Response.Write("<br/>E----" + Thread.CurrentThread.ManagedThreadId); await Task.Delay(2000); Response.Write("<br/>F----" + Thread.CurrentThread.ManagedThreadId); return 999; } protected async void Page_Load(object sender, EventArgs e) { Response.Write("<br/>A----" + Thread.CurrentThread.ManagedThreadId); var a=await FuncA(); Response.Write("<br/>B----" + Thread.CurrentThread.ManagedThreadId); } A----8 C----8 E----8 F----9 D----9 B----9編輯 2
(得到答案後)
似乎該執行緒僅在 GUI 應用程序中提供:。我在winform上執行這段程式碼
public async Task<int> FuncA() { textBox1.Text +=Environment.NewLine+ "\nC----" + Thread.CurrentThread.ManagedThreadId; var t = await FuncB(); textBox1.Text += Environment.NewLine + "\nD----" + Thread.CurrentThread.ManagedThreadId; return t; } public async Task<int> FuncB() { textBox1.Text += Environment.NewLine + "\nE----" + Thread.CurrentThread.ManagedThreadId; await Task.Delay(2000); textBox1.Text += Environment.NewLine + "\nF----" + Thread.CurrentThread.ManagedThreadId; return 999; } private async void Form1_Load(object sender, EventArgs e) { textBox1.Text += Environment.NewLine + "\nA----" + Thread.CurrentThread.ManagedThreadId; var a = await FuncA(); textBox1.Text += Environment.NewLine + "\nB----" + Thread.CurrentThread.ManagedThreadId; }
添加了 async/await 支持以幫助程序員編寫不會凍結的 GUI。在商店應用程序中特別有用,並且它被添加到 C# v5 的核心原因是,WinRT 是一個非常不友好的 api,它有許多非同步方法。
“保持在同一個執行緒上”場景在 GUI 應用程序中非常重要,這是必需的,因為 GUI 不是執行緒安全的。然而,它確實需要一個調度程序循環(又名 Application.Run),這是讓非同步程式碼在同一個執行緒上恢復的唯一方法。該循環是生產者-消費者問題的核心解決方案。
顯然你的程序沒有,看起來很像控制台模式應用程序。因此,您不會得到這種行為,它會在工作執行緒上恢復。
問題不大,您實際上並不需要它在同一個執行緒上恢復,因為無論如何控制台都是執行緒安全的。好吧,大多數情況下,當您要求輸入時,不包括在 .NET 4.5 中添加的鎖。當然,這也意味著您也沒有大量用於 async/await 的任務,Task 也可以正常工作。
如果我執行一個非同步方法並執行它,它肯定會在另一個執行緒上執行。
不,它通常在另一個執行緒上執行。它不一定在另一個執行緒上執行*。*
暫時停止思考執行緒,想想非同步的本質。非同步的本質是:
- 我有一些我目前正在執行的工作流程。
- 在獲得資訊 X 之前,我無法繼續此工作流程。
- 在我得到資訊 X 之前,我會做其他事情。
- 在未來的某個時候,一旦我有了 X,我將回到我在工作流程中中斷的地方並繼續。
假設您正在納稅,並且在這個複雜的工作流程中,您有大量的附加工作要執行。你可以執行一些操作然後記住你在哪裡,然後去吃午飯。然後回來再做幾個操作,然後記住你在哪裡,餵貓。然後回來再做幾個操作,然後記住你在哪裡,洗碗。然後完成計算,並從工作流程中斷的地方繼續。
這是一個非同步計算,但它只需要一個工作人員來完成。擁有多個工人只是一種特別方便的非同步方式,它不是必需的。
