操作系統(tǒng)的線程詳解
前言
這將是一個(gè)系列,一個(gè)關(guān)于進(jìn)程、線程和 協(xié)程的系列。
主要用于:回顧和復(fù)習(xí)以往所學(xué)的知識(shí) 以及 希望這點(diǎn)經(jīng)驗(yàn)?zāi)軌驇椭趯W(xué)習(xí)編程的你。
最初的幾章會(huì)講到一些相關(guān)的計(jì)算機(jī)理論知識(shí),可能相對(duì)枯燥。但這是基礎(chǔ),是理解后面程序必備的概念。如果有疑惑,可以加微信討論,咱們一起進(jìn)步。
線程的定義
線程(thread)是操作系統(tǒng)能夠進(jìn)行運(yùn)算的最小單位。同一進(jìn)程中的多條線程將共享該進(jìn)程中的全部系統(tǒng)資源,如虛擬地址空間,文件描述符和信號(hào)處理等等。
線程的實(shí)現(xiàn)方式
根據(jù)管理線程所發(fā)生的位置,我們將線程分為以下三類:
- 內(nèi)核支持線程內(nèi)核線程駐留在內(nèi)核空間,它們是內(nèi)核對(duì)象。有了內(nèi)核線程,每個(gè)用戶線程被映射或綁定到一個(gè)內(nèi)核線程。用戶線程在其生命期內(nèi)都會(huì)綁定到該內(nèi)核線程。一旦用戶線程終止,兩個(gè)線程都將離開系統(tǒng)。這被稱作”一對(duì)一”線程映射。優(yōu)點(diǎn)是調(diào)度靈活,缺點(diǎn)是內(nèi)核線程在用戶態(tài)和內(nèi)核態(tài)之間進(jìn)行上下文切換,資源開銷大。
- 用戶級(jí)線程內(nèi)核對(duì)線程包一無(wú)所知。從內(nèi)核角度考慮,就是按正常的方式管理,即單線程進(jìn)程(存在運(yùn)行時(shí)系統(tǒng))。也就是說(shuō),如果因?yàn)檫M(jìn)程中一個(gè)線程發(fā)生阻塞(如IO資源引起的阻塞),那么其他線程也將得不到執(zhí)行。
- 組合方式線程(posix線程調(diào)度模型,又稱posix規(guī)范)posix線程調(diào)度是一個(gè)混合模型,很靈活,足以在標(biāo)準(zhǔn)的特定實(shí)現(xiàn)中支持用戶級(jí)和內(nèi)核級(jí)的線程。模型中包括兩級(jí)調(diào)度–線程及和內(nèi)核實(shí)體級(jí)。線程級(jí)與用戶級(jí)線程類似,內(nèi)核實(shí)體由內(nèi)核調(diào)度。由線程庫(kù)來(lái)決定它需要多少內(nèi)核實(shí)體,以及他們是如何映射的。
上下文切換
- 什么是上下文切換?當(dāng)下計(jì)算機(jī)系統(tǒng)中,CPU運(yùn)行的線程數(shù)量遠(yuǎn)超過CPU的核數(shù),而用戶卻感覺這些程序在同時(shí)運(yùn)行。這得益于分時(shí)系統(tǒng)的設(shè)計(jì)理念——人們將CPU的時(shí)間劃分為若干小段。每個(gè)線程只能在其中有限個(gè)小段上執(zhí)行。待時(shí)間一到,CPU就會(huì)將線程掛起,使其進(jìn)入就緒狀態(tài),而CPU轉(zhuǎn)而執(zhí)行下一個(gè)線程,只不過這個(gè)切換的過程對(duì)于用戶來(lái)說(shuō)太快,感知不到而已。而在這一個(gè)過程中,CPU需要將當(dāng)前線程的工作環(huán)境保存起來(lái)(遷出工作區(qū)),然后將即將執(zhí)行的線程的數(shù)據(jù)載入工作區(qū),這一過程我們稱之為上下文切換。拓展,上面說(shuō)的是典型的被動(dòng)上下文切換,又稱之為飛自愿性上下文切換。除此之外,還有因當(dāng)前進(jìn)程資源不足發(fā)生的自愿性上下文切換,以及,中斷信號(hào)導(dǎo)致的中斷上下文切換。
- 上下文切換的成本我在控制臺(tái)查看一下自己系統(tǒng)中上下文切換的次數(shù)。(滿載狀態(tài)下)
- $ sar -w 1 10
- Linux 4.15.0-153-generic (ubuntu-bionic) 08/09/21 _x86_64_ (2 CPU)
- 15:26:02 proc/s cswch/s
- 15:26:03 0.00 65892.00
- 15:26:04 0.00 248868.00
- 15:26:05 0.00 368564.00
- 15:26:06 0.00 391488.00
- 15:26:07 0.00 349058.00
- 15:26:08 0.00 353089.00
- 15:26:09 0.00 381352.00
- 15:26:10 0.00 379659.00
- 15:26:11 0.00 374822.00
- 15:26:12 0.00 129233.00
- Average: 0.00 304202.50
- # proc/s 每秒創(chuàng)建的任務(wù)總數(shù)。
- # cswch/s 每秒上下文切換的總數(shù)
我這是2核CPU,據(jù)統(tǒng)計(jì)目前主流的CPU每次上下文切換要花掉2~5微秒。我們?nèi)≈形粩?shù)3微秒。我們來(lái)計(jì)算一下每秒單核CPU花在上下文切換中的時(shí)間:3*304202/2/1000=0.456s??梢钥闯?,頻繁的上下文切換對(duì)性能的影響是巨大的。
由于同一個(gè)進(jìn)程中的多個(gè)線程是共享進(jìn)程資源的,所以從這個(gè)角度我們又把上下文切換分成兩類:
- 進(jìn)程切換:不同進(jìn)程的線程之間切換。
- 線程切換:統(tǒng)一進(jìn)程中不同線程之間的切換。

上圖綠色的部分代表需要切換的上下文,我們可以看出,線程切換的開銷遠(yuǎn)小于進(jìn)程切換。
今天線程的理論只是就講到這里,接下來(lái)我們將以Python為主要編程語(yǔ)言,帶大家進(jìn)行 多線程實(shí)踐與性能分析,相對(duì)于干燥的理論知識(shí),將會(huì)變得比較有趣。