爲什麼直到IO操作完成後才睡眠線程會更有效率?
想想線程的工人。工人很貴。你想支付工人睡覺嗎?不是。你想支付工人儘可能多的工作。如果他們被阻止,你會讓他們在其他事情上工作,而不是在睡眠中清理堵塞。
線程非常昂貴。如果線程便宜,那麼肯定,我們可以賺很多錢。您只使用昂貴資源的池化策略。
線程的開銷主要有兩種:您提到堆棧的大小,即每個線程保留1MB的虛擬內存。但是,操作系統級別的成本也很高,對於擁有數千個線程的場景,這不是最優化的。確定接下來運行哪個線程,切換到上下文以及切換到哪個線程,所有這些成本都隨着線程數量的增加而增加。理想情況下,你需要n個處理器中的n個獨立線程,不多也不少。
畢竟,當線程返回到線程池時,它的堆棧需要保存在內存中以完成原始請求。
我不能讓這句話的頭,也沒有尾巴。當線程回到池中時,它的堆棧指針回到底部。
我的假設是,我們不能重新使用分配給線程的內存,除非我們在其他地方複製了使用的堆棧內存,並且複製數據可能會引入額外的開銷,這可能不合理。
我開始理解它。你的心智模式是:
- 堆棧是繼續的實現(我們接下來做什麼?)和激活(在這種方法激活當地人的值是什麼?)
- 等待完成的任務必須在工作流程中停止的位置繼續執行,而本地不變
- 因此必須在某處或某處複製繼續/激活信息 - 堆棧。
這個心理模型是合理的,但錯誤的。異步工作流構建狀態機,並將延續捆綁爲該機器中的狀態,然後將對狀態機的引用存儲在任務中。激活信息從堆棧槽中提升到閉包類的字段中。這會從堆棧和堆中獲得延續/激活信息。
現在請記住,任務的繼續不包含堆棧中的所有信息;它不是「當前持續調用」意義上的真正延續,它捕捉當前方法完成時發生的情況。它捕獲當目前等待任務完成,這足以發生了什麼。
請記住,堆棧只能用作「下一步要做什麼?」時繼續的具體化。工作流程是邏輯上堆棧 - 在這裏你接下來要做的就是堆棧頂部的東西。但異步工作流形成連接點等待的依賴關係樹;首先它不是一個堆棧,所以將堆棧作爲堆棧來表示是非啓動器。
當線程返回到池時,請求使用的堆棧內存會發生什麼變化?
只要線程繼續存在,爲線程堆棧保留的百萬字節的虛擬內存就會保留。這一點很重要!這是線程在.NET中如此昂貴的一個原因。虛擬內存的這1MB正在使用100%,只要操作系統的內存管理器而言,無論有多少是棧已經被推到。大部分1MB在其整個生命週期的大部分時間都是垃圾。
當線程返回池時,指向該棧的高水位標記的指針會移回開始處,並且超出它的所有內容現在都是垃圾。
如果我們不能重用內存,那麼重用線程有什麼意義?
我們可以重複使用內存;堆棧指針被重置。
如果是這樣,移動內存並重用未使用的堆棧內存可以提高總體效率嗎?
我不是追隨這個問題的主旨;我懷疑這是基於錯誤的前提。你能改述一下嗎?
這不是更有效,如果你嚴格地看着那一個單一的操作。如果你正在尋找一個應用程序,它使用多線程就像一個Web應用程序,其中線程都處於特別是高負載需求整體則變得高效的整體作爲被服務我線程/ O綁定的請求現在可以被釋放,以用於其他請求,而I/O完成。 – Igor
的可能的複製[爲什麼要使用異步請求,而不是使用更大的線程池?](HTTP://計算器。com/questions/9453560/why-use-async-requests-instead-of-using-a-greater-threadpool) – jlew
Thread.Sleep是一個阻塞調用。除非你正在測試一些冗長的操作,否則不要使用它。 https://stackoverflow.com/questions/8815895/why-is-thread-sleep-so-harmful –