簡體   English   中英

異步如何只在一個線程上工作?

[英]How can async only work on one thread?

如果某些代碼'等待'並且單個線程繼續運行程序,那么暫停的位如何恢復生命? 單個線程是否需要返回輪詢代碼的暫停狀態以查看它是否已完成?

MSDN文檔和我的介紹async博客文章都回答了這個問題。

總之,當async方法遇到尚未完成的操作的await ,默認情況下它將捕獲當前上下文。 這個“上下文”是當前的SynchronizationContext ,除非它是null ,在這種情況下它是當前的TaskScheduler 稍后,當操作完成時, async方法的其余部分將安排到該上下文。

在UI應用程序中,這可以是UI SynchronizationContext (在UI線程上調度方法)。 在ASP.NET應用程序中,這通常是請求上下文(未綁定到特定線程)。 如果您在線程池上運行async方法,則通常是線程池上下文(同樣,不綁定到任何特定線程)。

回到UI示例,UI線程確實有一個運行的中央“消息循環”,處理來自其隊列的Win32消息。 UI SynchronizationContext只是將消息發布到隊列,告訴UI線程執行async方法的下一部分。

[...]暫停的位怎么能恢復生機?

通過使用委托(取自msdn )。

“await”關鍵字告訴編譯器將可能的暫停/恢復點插入標記為“async”的方法中。

從邏輯上講,這意味着當您編寫“await someObject;”時,編譯器將生成檢查someObject表示的操作是否已完成的代碼。 如果有,則執行在等待點上同步繼續。 如果沒有,則生成的代碼將連續委托連接到等待的對象,這樣當表示的操作完成時,將調用該連續委托。 此繼續委托將重新輸入該方法,在此等待上一次調用停止的位置。 此時,無論等待對象在等待時是否已經完成,都將提取對象的任何結果,或者如果操作失敗,則將傳播任何發生的異常。


單個線程是否需要返回輪詢代碼的暫停狀態以查看它是否已完成?

不,沒有這樣的事情。 當你調用await ,來自當前線程的控制進入調用堆棧一步,即它返回給包含await的方法的被調用者。 任務完成后,TPL調用委托方法,該方法從await行恢復控制。

我實際上並不清楚具體如何在C#中實現await ,但是讓我提出一種可能的方式,只是回答“它怎么可能?”的問題。 (而不是“如何實施”?)。

首先考慮yield關鍵字,這是完全不同的,但我認為,更普遍的理解。 當你編寫一個返回IEnumerable<T>並在函數體內使用yield return的函數時,我們大多數人現在都明白C#編譯器會為你生成一個迭代器類 ,並產生與你的代碼看起來非常不同的IL中寫道。 我的觀點是我們必須意識到C#代碼本身並不總是非常清楚地映射到一組IL指令; 有時轉型很復雜。

這也必須是await的情況,其中C#編譯器不會簡單地為每行C#代碼發出一堆簡單的步驟。 例如,它可以做的是使用await進行調用,生成調用給定方法的委托,然后將方法代碼的其余部分捆綁為委托的回調。

異步操作的其他方法對於await關鍵字並不重要。 它可以在單獨的線程上執行工作,或執行一些I / O操作。 無論它做什么,它必須符合返回Task<T>的異步模式; 這是await依賴的。

IL中的結果函數在將剩余的邏輯添加為偵聽器以在完成單獨線程上的工作時接收信號之后將返回。 然后,該單獨的線程將消息發送回原始線程(在大多數情況下,實際上將是消息循環),以及對偵聽器的引用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM