ASP.NET 和非同步 - 它是如何工作的?
我知道這是一個常見問題,但我已經閱讀了大量文章並感到困惑。現在我認為最好不要閱讀它們))。
那麼,ASP.NET 是如何工作的(僅關於執行緒):
- http 請求由執行緒池中的執行緒提供服務。
- 當請求正在處理時,這個執行緒很忙,因為請求正在這個執行緒內處理。
- 當請求處理完成時,執行緒返迴執行緒池,伺服器發送響應。
這種描述的行為正確嗎?
當我在 ASP.NET MVC 控制器中啟動新任務時,究竟會發生什麼?
public ActionResult Index() { var task1 = Task.Factory.StartNew(() => DoSomeHeavyWork()); return View(); } private static async Task DoSomeHeavyWork() { await Task.Delay(5000); }
- 控制器動作開始在處理目前請求的執行緒內執行 - T1。
- 執行緒池為task1分配另一個執行緒(T2)。
- task1 在 T2 內“立即”啟動。
- 查看結果“立即”返回。
- ASP.NET 做一些工作,伺服器發送響應,T1 返迴執行緒池,T2 還活著。
- 在 DoSomeHeavyWork 完成一段時間後,T2 執行緒將返回到執行緒池。
這是正確的嗎 ?
現在讓我們看看非同步操作
public async Task<ActionResult> Index() { await DoSomeHeavyWork(); return View(); },我了解與以前的程式碼範例的區別,但不了解過程,在此範例中,行為如下:
- 動作開始在處理目前請求的執行緒內執行 - T1。
- DoSomeHeavyWork “立即”返回一個任務,我們也稱它為“task1”。
- T1 返迴執行緒池。
- DoSomeHeavyWork 完成後,Index 操作繼續執行。
- 索引操作執行後,伺服器將發送響應。
請解釋第 2 點和第 5 點之間發生的情況,問題是:
- DoSomeHeavyWork 是在 task1 內處理還是在哪裡(“等待”的地方)處理?我認為這是一個關鍵問題。
- 等待後哪個執行緒將繼續處理請求-執行緒池中的任何新執行緒,對嗎?
- request 產生從執行緒池分配的執行緒,但是在 DoSomeHeavyWorkAsync 完成之前不會發送響應,並且此方法在哪個執行緒中執行都沒有關係。換句話說,根據單個請求和單個具體任務(DoSomeHeavyWork),使用非同步沒有任何好處。這是正確的嗎 ?
- 如果前面的陳述是正確的,那麼我不明白非同步如何提高同一個請求的多個請求的性能任務。我會盡力解釋。假設執行緒池有 50 個執行緒可用於處理請求。單個請求至少應該由執行緒池中的一個執行緒處理,如果請求啟動了另一個執行緒,則所有執行緒都從執行緒池中取出,例如請求一個執行緒自己處理,並行啟動5個不同的任務並等待所有這些,執行緒池將有 50 - 1 - 5 = 44 個空閒執行緒來處理傳入請求 - 所以這是一種並行性,我們可以提高單個請求的性能,但我們減少了可以處理的請求數量。因此,根據 ASP.NET 中的請求處理,我認為只有以某種方式啟動 IO 完成執行緒的任務才能實現非同步(TAP)的目標。但是在這種情況下 IO 完成執行緒如何回調執行緒池執行緒呢?
這種描述的行為正確嗎?
是的。
這是正確的嗎 ?
是的。
DoSomeHeavyWork 是在 task1 內處理還是在哪裡(“等待”的地方)處理?我認為這是一個關鍵問題。
從目前程式碼來看,
DoSomeHeavyWork將非同步等待Task.Delay完成。是的,這將發生線上程池分配的同一個執行緒上,它不會旋轉任何新執行緒。但是,不能保證它會是同一個執行緒。await 之後哪個執行緒會繼續處理請求?
因為我們談論的是 ASP.NET,所以這將是一個任意的執行緒池執行緒,並在其上
HttpContext編組。如果這是 WinForms 或 WPF 應用程序,您將在 之後再次點擊 UI 執行緒await,因為您不使用ConfigureAwait(false).request 產生從執行緒池分配的執行緒,但是在 DoSomeHeavyWorkAsync 完成之前不會發送響應,並且此方法在哪個執行緒中執行都沒有關係。換句話說,根據單個請求和單個具體任務(DoSomeHeavyWork),使用非同步沒有任何好處。這是正確的嗎 ?
在這種特殊情況下,您不會看到非同步的好處。當您有並發請求訪問伺服器時,非同步會發光,並且其中很多都在執行 IO 綁定工作。例如,在訪問數據庫時使用非同步時,您可以在查詢執行的時間內釋放執行緒池執行緒,從而允許同一執行緒同時處理更多請求。
但是在這種情況下 IO 完成執行緒如何回調執行緒池執行緒呢?
您必須將並行性和並發性分開。如果您需要計算能力來並行執行 CPU 密集型工作,那麼非同步不是實現它的工具。另一方面,如果你有很多並發的IO 綁定操作,比如為 CRUD 操作訪問數據庫,你可以通過在 IO 操作執行時釋放執行緒來從非同步的使用中受益。這是非同步的主要關鍵點。
執行緒池具有專用的 IO 完成執行緒池以及工作執行緒,您可以通過呼叫
ThreadPool.GetAvailableThreads. 當您使用 IO 綁定操作時,檢索回調的執行緒通常是 IO 完成執行緒,而不是工作執行緒。他們都有不同的游泳池。