CPU 上下文切換是什麼意思?(上)

2021-10-05 16:02:53 字數 4386 閱讀 7163

我們都知道,linux 是乙個多工作業系統,它支援遠大於 cpu 數量的任務同時執行。當然,這些任務實際上並不是真的在同時執行,而是因為系統在很短的時間內,將 cpu 輪流分配給它們,造成多工同時執行的錯覺。

而在每個任務執行前,cpu 都需要知道任務從**載入、又從**開始執行,也就是說,需要系統事先幫它設定好cpu 暫存器和程式計數器(program counter,pc)。

cpu 暫存器,是 cpu 內建的容量小、但速度極快的記憶體。而程式計數器,則是用來儲存 cpu 正在執行的指令位置、或者即將執行的下一條指令位置。它們都是 cpu 在執行任何任務前,必須的依賴環境,因此也被叫做cpu 上下文

知道了什麼是 cpu 上下文,我想你也很容易理解cpu 上下文切換。cpu 上下文切換,就是先把前乙個任務的 cpu 上下文(也就是 cpu 暫存器和程式計數器)儲存起來,然後載入新任務的上下文到這些暫存器和程式計數器,最後再跳轉到程式計數器所指的新位置,執行新任務。

而這些儲存下來的上下文,會儲存在系統核心中,並在任務重新排程執行時再次載入進來。這樣就能保證任務原來的狀態不受影響,讓任務看起來還是連續執行。

所以,根據任務的不同,cpu 的上下文切換就可以分為幾個不同的場景,也就是程序上下文切換執行緒上下文切換以及中斷上下文切換

linux 按照特權等級,把程序的執行空間分為核心空間和使用者空間,分別對應著下圖中, cpu 特權等級的 ring 0 和 ring 3。

換個角度看,也就是說,程序既可以在使用者空間執行,又可以在核心空間中執行。程序在使用者空間執行時,被稱為程序的使用者態,而陷入核心空間的時候,被稱為程序的核心態。

從使用者態到核心態的轉變,需要通過系統呼叫來完成。比如,當我們檢視檔案內容時,就需要多次系統呼叫來完成:首先呼叫 open() 開啟檔案,然後呼叫 read() 讀取檔案內容,並呼叫 write() 將內容寫到標準輸出,最後再呼叫 close() 關閉檔案。

cpu 暫存器裡原來使用者態的指令位置,需要先儲存起來。接著,為了執行核心態**,cpu 暫存器需要更新為核心態指令的新位置。最後才是跳轉到核心態執行核心任務。

而系統呼叫結束後,cpu 暫存器需要恢復原來儲存的使用者態,然後再切換到使用者空間,繼續執行程序。所以,一次系統呼叫的過程,其實是發生了兩次 cpu 上下文切換。

不過,需要注意的是,系統呼叫過程中,並不會涉及到虛擬記憶體等程序使用者態的資源,也不會切換程序。這跟我們通常所說的程序上下文切換是不一樣的:

所以,系統呼叫過程通常稱為特權模式切換,而不是上下文切換。但實際上,系統呼叫過程中,cpu 的上下文切換還是無法避免的。

那麼,程序上下文切換跟系統呼叫又有什麼區別呢?

首先,你需要知道,程序是由核心來管理和排程的,程序的切換只能發生在核心態。所以,程序的上下文不僅包括了虛擬記憶體、棧、全域性變數等使用者空間的資源,還包括了核心堆疊、暫存器等核心空間的狀態。

因此,程序的上下文切換就比系統呼叫時多了一步:在儲存當前程序的核心狀態和 cpu 暫存器之前,需要先把該程序的虛擬記憶體、棧等儲存下來;而載入了下一程序的核心態後,還需要重新整理程序的虛擬記憶體和使用者棧。

如下圖所示,儲存上下文和恢復上下文的過程並不是「免費」的,需要核心在 cpu 上執行才能完成。

根據tsuna 的測試報告,每次上下文切換都需要幾十納秒到數微秒的 cpu 時間。這個時間還是相當可觀的,特別是在程序上下文切換次數較多的情況下,很容易導致 cpu 將大量時間耗費在暫存器、核心棧以及虛擬記憶體等資源的儲存和恢復上,進而大大縮短了真正執行程序的時間。這也正是上一節中我們所講的,導致平均負載公升高的乙個重要因素。

另外,我們知道, linux 通過 tlb(translation lookaside buffer)來管理虛擬記憶體到物理記憶體的對映關係。當虛擬記憶體更新後,tlb 也需要重新整理,記憶體的訪問也會隨之變慢。特別是在多處理器系統上,快取是被多個處理器共享的,重新整理快取不僅會影響當預處理器的程序,還會影響共享快取的其他處理器的程序。

知道了程序上下文切換潛在的效能問題後,我們再來看,究竟什麼時候會切換程序上下文。

顯然,程序切換時才需要切換上下文,換句話說,只有在程序排程的時候,才需要切換上下文。linux 為每個 cpu 都維護了乙個就緒佇列,將活躍程序(即正在執行和正在等待 cpu 的程序)按照優先順序和等待 cpu 的時間排序,然後選擇最需要 cpu 的程序,也就是優先順序最高和等待 cpu 時間最長的程序來執行。

那麼,程序在什麼時候才會被排程到 cpu 上執行呢?

最容易想到的乙個時機,就是程序執行完終止了,它之前使用的 cpu 會釋放出來,這個時候再從就緒佇列裡,拿乙個新的程序過來執行。其實還有很多其他場景,也會觸發程序排程,在這裡我給你逐個梳理下。

其一,為了保證所有程序可以得到公平排程,cpu 時間被劃分為一段段的時間片,這些時間片再**流分配給各個程序。這樣,當某個程序的時間片耗盡了,就會被系統掛起,切換到其它正在等待 cpu 的程序執行。

其二,程序在系統資源不足(比如記憶體不足)時,要等到資源滿足後才可以執行,這個時候程序也會被掛起,並由系統排程其他程序執行。

其三,當程序通過睡眠函式 sleep 這樣的方法將自己主動掛起時,自然也會重新排程。

其四,當有優先順序更高的程序執行時,為了保證高優先順序程序的執行,當前程序會被掛起,由高優先順序程序來執行。

最後乙個,發生硬體中斷時,cpu 上的程序會被中斷掛起,轉而執行核心中的中斷服務程式。

了解這幾個場景是非常有必要的,因為一旦出現上下文切換的效能問題,它們就是幕後**。

說完了程序的上下文切換,我們再來看看執行緒相關的問題。

執行緒與程序最大的區別在於,執行緒是排程的基本單位,而程序則是資源擁有的基本單位。說白了,所謂核心中的任務排程,實際上的排程物件是執行緒;而程序只是給執行緒提供了虛擬記憶體、全域性變數等資源。所以,對於執行緒和程序,我們可以這麼理解:

這麼一來,執行緒的上下文切換其實就可以分為兩種情況:

第一種, 前後兩個執行緒屬於不同程序。此時,因為資源不共享,所以切換過程就跟程序上下文切換是一樣。

第二種,前後兩個執行緒屬於同乙個程序。此時,因為虛擬記憶體是共享的,所以在切換時,虛擬記憶體這些資源就保持不動,只需要切換執行緒的私有資料、暫存器等不共享的資料。

到這裡你應該也發現了,雖然同為上下文切換,但同程序內的執行緒切換,要比多程序間的切換消耗更少的資源,而這,也正是多執行緒代替多程序的乙個優勢。

除了前面兩種上下文切換,還有乙個場景也會切換 cpu 上下文,那就是中斷。

為了快速響應硬體的事件,中斷處理會打斷程序的正常排程和執行,轉而呼叫中斷處理程式,響應裝置事件。而在打斷其他程序時,就需要將程序當前的狀態儲存下來,這樣在中斷結束後,程序仍然可以從原來的狀態恢復執行。

跟程序上下文不同,中斷上下文切換並不涉及到程序的使用者態。所以,即便中斷過程打斷了乙個正處在使用者態的程序,也不需要儲存和恢復這個程序的虛擬記憶體、全域性變數等使用者態資源。中斷上下文,其實只包括核心態中斷服務程式執行所必需的狀態,包括 cpu 暫存器、核心堆疊、硬體中斷引數等。

對同乙個 cpu 來說,中斷處理比程序擁有更高的優先順序,所以中斷上下文切換並不會與程序上下文切換同時發生。同樣道理,由於中斷會打斷正常程序的排程和執行,所以大部分中斷處理程式都短小精悍,以便盡可能快的執行結束。

另外,跟程序上下文切換一樣,中斷上下文切換也需要消耗 cpu,切換次數過多也會耗費大量的 cpu,甚至嚴重降低系統的整體效能。所以,當你發現中斷次數過多時,就需要注意去排查它是否會給你的系統帶來嚴重的效能問題。

總結一下,不管是哪種場景導致的上下文切換,你都應該知道:

cpu 上下文切換,是保證 linux 系統正常工作的核心功能之一,一般情況下不需要我們特別關注。

但過多的上下文切換,會把 cpu 時間消耗在暫存器、核心棧以及虛擬記憶體等資料的儲存和恢復上,從而縮短進**正執行的時間,導致系統的整體效能大幅下降。

把何炅說過的那句我特別認同的雞湯送給你,「想要得到你就要學會付出,要付出還要堅持;如果你真的覺得很難,那你就放棄,如果你放棄了就不要抱怨。人生就是這樣,世界是平衡的,每個人都是通過自己的努力,去決定自己生活的樣子。」 歡迎加入qq群:725967421     一起交流,一起進步!!

CPU 上下文切換是什麼

linux 是乙個多工作業系統,它支援遠大於 cpu 數量的任務同時執行。當然,這些任務實際上並不是真的在同時執行,而是因為系統在很短的時間內,將 cpu 輪流分配給它們,造成多工同時執行的錯覺 而在每個任務執行前,cpu 都需要知道任務從 載入 又從 開始執行,也就是說,需要系統事先幫它設定好 c...

CPU上下文切換

linux任務執行前,cpu都要知道從任務從 載入 又從 開始執行,也就是說,需要系統事先幫它設定好cpu暫存器和程式計數器 cpu上下文 cpu暫存器和程式計數器 cpu暫存器 cpu內建容量小 速度極快的記憶體 程式計數器 儲存cpu正在執行的指令位置 或者即將執行的下一條指令位置 把前乙個任務...

CPU 上下文切換

乙個酒店,裡面滿滿的客人在吃飯,好比是,酒店裡面的所有人速速離開酒店,讓下一波客人吃。好比是 酒店裡的客人不需要離開酒店,但是服務員就是不給他們上菜,因為服務員去給 vip 客戶服務去了,好在 vip 客戶比較好說話,很快就伺候好了,服務員再來給酒店裡的客人服務 不好意思,這道菜的工序比較複雜,讓您...