線程上下文切換

            一、爲什麼要減少線程上下文切換
                當CPU從執行一個線程切換到執行另外一個線程的時候,它需要先存儲當前線程的本地的數據,程序指針等,然後載入另一個線程的本地數據,程序指針等,最後纔開始執行。這種切換稱爲“上下文切換”(“context switch”)。CPU會在一個上下文中執行一個線程,然後切換到另外一個上下文中執行另外一個線程。上下文切換並不廉價,是比較耗時的
            二、線程上下文切換髮生的條件
                1.中斷處理:中斷分爲硬件中斷和軟件中斷,軟件中斷包括因爲IO阻塞、未搶到資源或者用戶代碼等原因,線程被掛起
                2.多任務處理:每個程序都有相應的時間處理片,當前任務的時間片用完之後,系統CPU正常調度下一個任務
                3.用戶狀態切換:這種情況下,上下文切換並非一定發生,只在特定操作系統纔會發生上下文切換
            三、上下文切換的步驟
                1.爲了理解爲什麼上下文切換的時候會損耗性能,我們應該先看看上下文切換的過程中究竟發生了什麼。在切換過程中,正在執行的進程的狀態必須以某種方式存儲起來,這樣在未來才能被恢復。這裏說的進程狀態包括該進程正在使用的所有寄存器(尤其是程序計數器),和一些必要的操作系統數據。保存進程狀態的數據結構叫做“進程控制塊”(PCB,process control block);
                2.PCB通常是系統內存佔用區中的一個連續存區,它存放着操作系統用於描述進程情況及控制進程運行所需的全部信息,它使一個在多道程序環境下不能獨立運行的程序成爲一個能獨立運行的基本單位或一個能與其他進程併發執行的進程。
                上下文切換的具體步驟是(假設當前進程是進程A,要切換到的下一個進程是進程B):
                    1.保存進程A的狀態(寄存器和操作系統數據);
                    2.更新PCB中的信息,對進程A的“運行態”做出相應更改;
                    3.將進程A的PCB放入相關狀態的隊列;
                    4.將進程B的PCB信息改爲“運行態”,並執行進程B;
                    5.B執行完後,從隊列中取出進程A的PCB,恢復進程A被切換時的上下文,繼續執行A。
                    6.線程分爲用戶級線程和內核級線程。同一進程中的用戶級線程切換的時候,只需要保存用戶寄存器的內容,程序計數器,棧指針,不需要模式切換。但是這樣會導致線程阻塞和無法利用多處理器。而同一進程中的內核級線程切換的時候,就克服了這兩個缺點,但是除了保存上下文,還要進行模式切換。
                線程切換和進程切換的步驟不同。進程的上下文切換分爲兩步:1.切換頁目錄以使用新的地址空間;2.切換內核棧和硬件上下文。對於linux來說,線程和進程的最大區別就在於地址空間。對於線程切換,第1步是不需要做的,第2是進程和線程切換都要做的。所以明顯是進程切換代價大。線程上下文切換和進程上下文切換一個最主要的區別是線程的切換虛擬內存空間依然是相同的,但是進程切換是不同的。這兩種上下文切換的處理都是通過操作系統內核來完成的。內核的這種切換過程伴隨的最顯著的性能損耗是將寄存器中的內容切換出。
            四、如何減少線程上下文切換
                    1.無鎖併發編程:多線程競爭鎖時,會引起上下文切換,所以多線程處理數據時,可以用一些辦法來避免使用鎖,如將數據的ID按照Hash算法取模分段,不同的線程處理不同段的數據。 
                    2.CAS算法:Java的Atomic包使用CAS(compare and swap)算法來更新數據,而不需要加鎖。 
                    3.使用最少線程:避免創建不需要的線程,比如任務很少,但是創建了很多線程來處理,這樣會造成大量線程都處於等待狀態。 
                    4.協程:在單線程裏實現多任務的調度,並在單線程裏維持多個任務間的切換。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章