前言
併發程式設計的目的是為了讓程式執行得更快,但是並不是啟動更多的執行緒就能讓程式最大限度地併發執行。在進行併發程式設計時,如果希望通過多執行緒執行任務讓程式執行得更快,會面臨非常多的挑戰,比如上下文切換的問題、死鎖的問題,以及受限於硬體和軟體的資源限制問題,本文要研究的是上下文切換的問題。
什麼是上下文切換
即使是單核cpu也支援多執行緒執行**,cpu通過給每個執行緒分配cpu時間片來實現這個機制。時間片是cpu分配給各個執行緒的時間,因為時間片非常短,所以cpu通過不停地切換執行緒執行,讓我們感覺多個執行緒時同時執行的,時間片一般是幾十毫秒(ms)。
cpu通過時間片分配演算法來迴圈執行任務,當前任務執行乙個時間片後會切換到下乙個任務。但是,在切換前會儲存上乙個任務的狀態,以便下次切換回這個任務時,可以再次載入這個任務的狀態,從任務儲存到再載入的過程就是一次上下文切換。
這就像我們同時讀兩本書,當我們在讀一本英文的技術書籍時,發現某個單詞不認識,於是便開啟中英文詞典,但是在放下英文書籍之前,大腦必須先記住這本書讀到了多少頁的第多少行,等查完單詞之後,能夠繼續讀這本書。這樣的切換是會影響讀書效率的,同樣上下文切換也會影響多執行緒的執行速度。
上下文切換**測試
1修改上面的count值,即修改迴圈次數,看一下序列執行和併發執行的時間測試結果:public
class
contextswitchtest210
11private
static
void concurrency() throws
exception
1222}23
});24
thread.start();
25int b = 0;
26for (long i = 0; i < count; i++)
2730
thread.join();
31long time = system.currenttimemillis() -start;
32 system.out.println("concurrency:" + time + "ms, b = " +b);33}
3435
private
static
void
serial()
3643
int b = 0;
44for (int i = 0; i < count; i++)
4548
long time = system.currenttimemillis() -start;
49 system.out.println("serial:" + time + "ms, b = " + b + ", a = " +a);50}
51 }
迴圈次數序列執行耗時/ms併發執行耗時/ms序列和併發對比
1億78
50併發快約0.5倍
1000萬106
併發快約0.5~1倍
100萬32
差不多10萬22
差不多1萬01
差不多,十幾次執行下來,總體而言序列略快
從表中可以看出,100次併發執行累加以下,序列執行和併發執行的執行速度總體而言差不多,1萬次以下序列執行甚至還可以說是略快。為什麼併發執行的速度會比序列慢呢?這就是因為執行緒有建立和上下文切換的開銷。
引起執行緒上下文切換的原因
對於我們經常使用的搶占式作業系統而言,引起執行緒上下文切換的原因大概有以下幾種:
當前執行任務的時間片用完之後,系統cpu正常排程下乙個任務
當前執行任務碰到io阻塞,排程器將此任務掛起,繼續下一任務
多個任務搶占鎖資源,當前任務沒有搶到鎖資源,被排程器掛起,繼續下一任務
使用者**掛起當前任務,讓出cpu時間
硬體中斷
上下文切換次數檢視
在linux系統下可以使用vmstat命令來檢視上下文切換的次數,下面是利用vmstat檢視上下文切換次數的示例:
cs(context switch)表示上下文切換的次數,從圖中可以看到,上下文每秒鐘切換500~600次左右。
如果要檢視上下文切換的時長,可以利用lmbench3,這是乙個效能分析工具。
如何減少上下文切換
既然上下文切換會導致額外的開銷,因此減少上下文切換次數便可以提高多執行緒程式的執行效率。減少上下文切換的方法有無鎖併發程式設計、cas演算法、使用最少執行緒和使用協程。
多執行緒上下文切換
在上下文切換過程中,cpu會停止處理當前執行的程式,並儲存當前程式執行的具體位置以便之後繼續執行。從這個角度來看,上下文切換有點像我們同時閱讀幾本書,在來回切換書本的同時我們需要記住每本書當前讀到的頁碼。在程式中,上下文切換過程中的 頁碼 資訊是儲存在程序控制塊 pcb 中的。pcb還經常被稱作 切...
多執行緒上下文切換
什麼是上下文切換 上下文切換 context switching 是儲存和恢復cpu狀態的過程,它使得執行緒執行能夠從中斷點恢復執行。上下文切換時多工作業系統和多執行緒環境的基本特徵。即使是單核cpu也支援多執行緒執行 cpu通過給每個執行緒分配cpu時間片來實現這個機制。時間片是cpu分配給各個執...
多執行緒 上下文切換
多執行緒程式設計中一般執行緒的個數都大於 cpu 核心的個數,而乙個 cpu 核心在任意時刻只能被乙個執行緒使用,為了讓這些執行緒都能得到有效執行,cpu 採取的策略是為每個執行緒分配時間片並輪轉的形式。當乙個執行緒的時間片用完的時候就會重新處於就緒狀態讓給其他執行緒使用,這個過程就屬於一次上下文切...