Dot-Net

我對 async/await、它的工作原理和好處的理解是否正確?

  • August 8, 2015

我曾多次斷言我對 async/await 的理解,經常爭論我是否正確。如果有人能證實或否認我的理解,並澄清任何誤解,我將不勝感激,以免我傳播錯誤資訊。

高層理解

async/await是一種在編寫非同步程式碼時避免回調地獄的方法。正在執行非同步方法的執行緒在遇到 時將返迴執行緒池await,並在等待的操作完成後繼續執行。

低層次的理解

JIT 會將非同步方法拆分為圍繞await點的離散部分,允許在保留方法狀態的情況下重新進入方法。在幕後,這涉及某種狀態機。

與並發的關係

async/await並不意味著任何形式的並發。使用async/編寫的應用程序await可以完全是單執行緒的,同時仍然可以獲得所有好處,就像 node.js 所做的那樣,儘管有回調。與 node.js 不同,.NET 是多執行緒的,因此通過使用async/ await,您可以在不使用回調的情況下獲得非阻塞 IO 的好處,同時還可以擁有多個執行執行緒。

好處

async/await在等待 IO 完成時釋放執行緒來做其他事情。它還可以與TPL結合使用,在多個執行緒或 UI 執行緒之外執行 CPU 密集型工作。

為了從非阻塞 IO 中受益,非同步方法需要建構在 API 之上,這些 API實際上利用了最終由作業系統提供的非阻塞 IO。

濫用

這是我理解的最大爭論點。很多人認為將阻塞操作包裝在 a 中Task並使用async/await會帶來性能提升。通過創建一個額外的執行緒來處理操作,將原始執行緒返回到執行緒池,然後在任務完成後恢復原始方法,所發生的一切都是不必要的上下文切換,而不是真正釋放執行緒來做其他工作。雖然這不像 TPL 那樣濫用async/ await,但這種心態似乎源於對async/的誤解await

這是非常正確的。

不過有幾點注意事項:

  • 開始執行非同步方法的執行緒是呼叫者的執行緒,它可能是也可能不是ThreadPool執行緒。
  • 如果到達等待,但等待的(通常Task)已經完成,執行緒將繼續同步執行其餘的方法。
  • 恢復執行該方法的執行緒通常是一個ThreadPool執行緒,但這取決於SyncrhonizationContextand TaskScheduler
  • 這裡不涉及 JIT(不比平時多)。編譯器是將非同步方法轉換為狀態機的編譯器。您可以通過這個 TryRoslyn 範例看到這一點。
  • 確實,async-await 不一定意味著並發,因為它可能是單執行緒的。但是,通過同時啟動和等待多個非同步操作,即使只有一個執行緒,它仍然可以並發。
  • async-await 和 TPL 不是完全獨立的部分。async-await 建立在 TPL 之上。這就是為什麼它被稱為基於任務的非同步模式。
  • 雖然大多數真正的非同步操作都是 I/O,但並非全部都是。您通常還Task.Delay使用非同步同步結構(如SemaphoreSlim.WaitAsync.

引用自:https://stackoverflow.com/questions/31899407