日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

進(jìn)程是操作系統(tǒng)的偉大發(fā)明之一,對應(yīng)用程序屏蔽了CPU調(diào)度、內(nèi)存管理等硬件細(xì)節(jié),而抽象出一個(gè)進(jìn)程的概念,讓應(yīng)用程序?qū)P挠趯?shí)現(xiàn)自己的業(yè)務(wù)邏輯既可,而且在有限的CPU上可以“同時(shí)”進(jìn)行許多個(gè)任務(wù)。但是它為用戶帶來方便的同時(shí),也引入了一些額外的開銷。如下圖,在進(jìn)程運(yùn)行中間的時(shí)間里,雖然CPU也在忙于干活,但是卻沒有完成任何的用戶工作,這就是進(jìn)程機(jī)制帶來的額外開銷。

 

進(jìn)程/線程上下文切換會用掉你多少CPU?

 

 

圖1.jpg

在進(jìn)程A切換到進(jìn)程B的過程中,先保存A進(jìn)程的上下文,以便于等A恢復(fù)運(yùn)行的時(shí)候,能夠知道A進(jìn)程的下一條指令是啥。然后將要運(yùn)行的B進(jìn)程的上下文恢復(fù)到寄存器中。這個(gè)過程被稱為上下文切換。上下文切換開銷在進(jìn)程不多、切換不頻繁的應(yīng)用場景下問題不大。但是現(xiàn)在linux操作系統(tǒng)被用到了高并發(fā)的網(wǎng)絡(luò)程序后端服務(wù)器。在單機(jī)支持成千上萬個(gè)用戶請求的時(shí)候,這個(gè)開銷就得拿出來說道說道了。因?yàn)橛脩暨M(jìn)程在請求redis、MySQL數(shù)據(jù)等網(wǎng)絡(luò)IO阻塞掉的時(shí)候,或者在進(jìn)程時(shí)間片到了,都會引發(fā)上下文切換。

 

進(jìn)程/線程上下文切換會用掉你多少CPU?

 

 

圖2.png

一個(gè)簡單的進(jìn)程上下文切換開銷測試實(shí)驗(yàn)

廢話不多說,我們先用個(gè)實(shí)驗(yàn)測試一下,到底一次上下文切換需要多長的CPU時(shí)間!實(shí)驗(yàn)方法是創(chuàng)建兩個(gè)進(jìn)程并在它們之間傳送一個(gè)令牌。其中一個(gè)進(jìn)程在讀取令牌時(shí)就會引起阻塞。另一個(gè)進(jìn)程發(fā)送令牌后等待其返回時(shí)也處于阻塞狀態(tài)。如此往返傳送一定的次數(shù),然后統(tǒng)計(jì)他們的平均單次切換時(shí)間開銷。

具體的實(shí)驗(yàn)代碼參見test04

# gcc main.c -o main
# ./main./main
Before Context Switch Time1565352257 s, 774767 us
After Context SWitch Time1565352257 s, 842852 us

每次執(zhí)行的時(shí)間會有差異,多次運(yùn)行后平均每次上下文切換耗時(shí)3.5us左右。當(dāng)然了這個(gè)數(shù)字因機(jī)器而異,而且建議在實(shí)機(jī)上測試。

前面我們測試系統(tǒng)調(diào)用的時(shí)候,最低值是200ns??梢姡舷挛那袚Q開銷要比系統(tǒng)調(diào)用的開銷要大。系統(tǒng)調(diào)用只是在進(jìn)程內(nèi)將用戶態(tài)切換到內(nèi)核態(tài),然后再切回來,而上下文切換可是直接從進(jìn)程A切換到了進(jìn)程B。顯然這個(gè)上下文切換需要完成的工作量更大。

進(jìn)程上下文切換開銷都有哪些

那么上下文切換的時(shí)候,CPU的開銷都具體有哪些呢?開銷分成兩種,一種是直接開銷、一種是間接開銷。

直接開銷就是在切換時(shí),cpu必須做的事情,包括:

  • 1、切換頁表全局目錄
  • 2、切換內(nèi)核態(tài)堆棧
  • 3、切換硬件上下文(進(jìn)程恢復(fù)前,必須裝入寄存器的數(shù)據(jù)統(tǒng)稱為硬件上下文)
  • ip(instruction pointer):指向當(dāng)前執(zhí)行指令的下一條指令
  • bp(base pointer): 用于存放執(zhí)行中的函數(shù)對應(yīng)的棧幀的棧底地址
  • sp(stack poinger): 用于存放執(zhí)行中的函數(shù)對應(yīng)的棧幀的棧頂?shù)刂?/li>
  • cr3:頁目錄基址寄存器,保存頁目錄表的物理地址
  • ......
  • 4、刷新TLB
  • 5、系統(tǒng)調(diào)度器的代碼執(zhí)行

間接開銷主要指的是雖然切換到一個(gè)新進(jìn)程后,由于各種緩存并不熱,速度運(yùn)行會慢一些。如果進(jìn)程始終都在一個(gè)CPU上調(diào)度還好一些,如果跨CPU的話,之前熱起來的TLB、L1、L2、L3因?yàn)檫\(yùn)行的進(jìn)程已經(jīng)變了,所以以局部性原理cache起來的代碼、數(shù)據(jù)也都沒有用了,導(dǎo)致新進(jìn)程穿透到內(nèi)存的IO會變多。 其實(shí)我們上面的實(shí)驗(yàn)并沒有很好地測量到這種情況,所以實(shí)際的上下文切換開銷可能比3.5us要大。

想了解更詳細(xì)操作過程的同學(xué)請參考《深入理解Linux內(nèi)核》中的第三章和第九章。

一個(gè)更為專業(yè)的測試工具-lmbench

lmbench用于評價(jià)系統(tǒng)綜合性能的多平臺開源benchmark,能夠測試包括文檔讀寫、內(nèi)存操作、進(jìn)程創(chuàng)建銷毀開銷、網(wǎng)絡(luò)等性能。使用方法簡單,但就是跑有點(diǎn)慢,感興趣的同學(xué)可以自己試一試。

這個(gè)工具的優(yōu)勢是是進(jìn)行了多組實(shí)驗(yàn),每組2個(gè)進(jìn)程、8個(gè)、16個(gè)。每個(gè)進(jìn)程使用的數(shù)據(jù)大小也在變,充分模擬cache miss造成的影響。我用他測了一下結(jié)果如下:

-------------------------------------------------------------------------
Host OS 2p/0K 2p/16K 2p/64K 8p/16K 8p/64K 16p/16K 16p/64K 
 ctxsw ctxsw ctxsw ctxsw ctxsw ctxsw ctxsw 
--------- ------------- ------ ------ ------ ------ ------ ------- ------- 
bjzw_46_7 Linux 2.6.32- 2.7800 2.7800 2.7000 4.3800 4.0400 4.75000 5.48000 

lmbench顯示的進(jìn)程上下文切換耗時(shí)從2.7us到5.48之間。

線程上下文切換耗時(shí)

前面我們測試了進(jìn)程上下文切換的開銷,我們再繼續(xù)在Linux測試一下線程。看看究竟比進(jìn)程能不能快一些,快的話能快多少。

在Linux下其實(shí)本并沒有線程,只是為了迎合開發(fā)者口味,搞了個(gè)輕量級進(jìn)程出來就叫做了線程。輕量級進(jìn)程和進(jìn)程一樣,都有自己獨(dú)立的task_struct進(jìn)程描述符,也都有自己獨(dú)立的pid。從操作系統(tǒng)視角看,調(diào)度上和進(jìn)程沒有什么區(qū)別,都是在等待隊(duì)列的雙向鏈表里選擇一個(gè)task_struct切到運(yùn)行態(tài)而已。只不過輕量級進(jìn)程和普通進(jìn)程的區(qū)別是可以共享同一內(nèi)存地址空間、代碼段、全局變量、同一打開文件集合而已。

同一進(jìn)程下的線程之所有g(shù)etpid()看到的pid是一樣的,其實(shí)task_struct里還有一個(gè)tgid字段。 對于多線程程序來說,getpid()系統(tǒng)調(diào)用獲取的實(shí)際上是這個(gè)tgid,因此隸屬同一進(jìn)程的多線程看起來PID相同。

我們用一個(gè)實(shí)驗(yàn)來測試一下test06。其原理和進(jìn)程測試差不多,創(chuàng)建了20個(gè)線程,在線程之間通過管道來傳遞信號。接到信號就喚醒,然后再傳遞信號給下一個(gè)線程,自己睡眠。 這個(gè)實(shí)驗(yàn)里單獨(dú)考慮了給管道傳遞信號的額外開銷,并在第一步就統(tǒng)計(jì)了出來。

# gcc -lpthread main.c -o main
0.508250 
4.363495 

每次實(shí)驗(yàn)結(jié)果會有一些差異,上面的結(jié)果是取了多次的結(jié)果之后然后平均的,大約每次線程切換開銷大約是3.8us左右。從上下文切換的耗時(shí)上來看,Linux線程(輕量級進(jìn)程)其實(shí)和進(jìn)程差別不太大。

Linux相關(guān)命令

既然我們知道了上下文切換比較的消耗CPU時(shí)間,那么我們通過什么工具可以查看一下Linux里究竟在發(fā)生多少切換呢?如果上下文切換已經(jīng)影響到了系統(tǒng)整體性能,我們有沒有辦法把有問題的進(jìn)程揪出來,并把它優(yōu)化掉呢?

# vmstat 1 
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- 
 r b swpd free buff cache si so bi bo in cs us sy id wa st 
 2 0 0 595504 5724 190884 0 0 295 297 0 0 14 6 75 0 4 
 5 0 0 593016 5732 193288 0 0 0 92 19889 29104 20 6 67 0 7 
 3 0 0 591292 5732 195476 0 0 0 0 20151 28487 20 6 66 0 8 
 4 0 0 589296 5732 196800 0 0 116 384 19326 27693 20 7 67 0 7 
 4 0 0 586956 5740 199496 0 0 216 24 18321 24018 22 8 62 0 8 

或者是

# sar -w 1 
proc/s 
 Total number of tasks created per second. 
cswch/s 
 Total number of context switches per second. 
11:19:20 AM proc/s cswch/s 
11:19:21 AM 110.28 23468.22 
11:19:22 AM 128.85 33910.58 
11:19:23 AM 47.52 40733.66 
11:19:24 AM 35.85 30972.64 
11:19:25 AM 47.62 24951.43 
11:19:26 AM 47.52 42950.50 
...... 

上圖的環(huán)境是一臺生產(chǎn)環(huán)境機(jī)器,配置是8核8G的KVM虛機(jī),環(huán)境是在Nginx+fpm的,fpm數(shù)量為1000,平均每秒處理的用戶接口請求大約100左右。其中cs列表示的就是在1s內(nèi)系統(tǒng)發(fā)生的上下文切換次數(shù),大約1s切換次數(shù)都達(dá)到4W次了。粗略估算一下,每核大約每秒需要切換5K次,則1s內(nèi)需要花將近20ms在上下文切換上。要知道這是虛機(jī),本身在虛擬化上還會有一些額外開銷,而且還要真正消耗CPU在用戶接口邏輯處理、系統(tǒng)調(diào)用內(nèi)核邏輯處理、以及網(wǎng)絡(luò)連接的處理以及軟中斷,所以20ms的開銷實(shí)際上不低了。

那么進(jìn)一步,我們看下到底是哪些進(jìn)程導(dǎo)致了頻繁的上下文切換?

# pidstat -w 1 
11:07:56 AM PID cswch/s nvcswch/s Command
11:07:56 AM 32316 4.00 0.00 php-fpm 
11:07:56 AM 32508 160.00 34.00 php-fpm 
11:07:56 AM 32726 131.00 8.00 php-fpm 
...... 

由于fpm是同步阻塞的模式,每當(dāng)請求Redis、Memcache、Mysql的時(shí)候就會阻塞導(dǎo)致cswch/s自愿上下文切換,而只有時(shí)間片到了之后才會觸發(fā)nvcswch/s非自愿切換??梢奻pm進(jìn)程大部分的切換都是自愿的、非自愿的比較少。

如果想查看具體某個(gè)進(jìn)程的上下文切換總情況,可以在/proc接口下直接看,不過這個(gè)是總值。

grep ctxt /proc/32583/status 
voluntary_ctxt_switches: 573066 
nonvoluntary_ctxt_switches: 89260 

本節(jié)結(jié)論

上下文切換具體做哪些事情我們沒有必要記,只需要記住一個(gè)結(jié)論既可,測得作者開發(fā)機(jī)上下文切換的開銷大約是2.7-5.48us左右,你自己的機(jī)器可以用我提供的代碼或工具進(jìn)行一番測試。

lmbench相對更準(zhǔn)確一些,因?yàn)榭紤]了切換后Cache miss導(dǎo)致的額外開銷。

個(gè)人公眾號“開發(fā)內(nèi)功管理”,打通理論與實(shí)踐的任督二脈。

參考文獻(xiàn)

  • 進(jìn)程上下文切換,殘酷的性能殺手
  • 測試上下文切換開銷
  • 進(jìn)程上下文切換導(dǎo)致Load過高
  • CPU上下文切換的次數(shù)和時(shí)間
  • Linux操作系統(tǒng)測試工具
  • lmbench官方文檔
  • lmbench安裝與使用

分享到:
標(biāo)簽:線程
用戶無頭像

網(wǎng)友整理

注冊時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定