前言
在打算寫這篇多線層底層實(shí)現(xiàn)機(jī)制的時(shí)候,突然發(fā)現(xiàn)自己對(duì)于計(jì)算機(jī)竟然懂得這么表面赁濒,對(duì)于CPU的工作原理都不完全清楚轨奄,于是又轉(zhuǎn)頭查看了一些CPU相關(guān)的資料。也不敢鉆的太深拒炎,怕自己迷路...挪拟,其中如有錯(cuò)誤,望知道的朋友在下面留言評(píng)論击你,我會(huì)及時(shí)更新的舞丛。
關(guān)于CPU
CPU(中央處理器)顧名思義是電腦中處理器的總部(電腦里幾個(gè)重要的硬件都自帶的有自己的處理器,比如果漾,GPU是顯卡自己的處理器等)球切,負(fù)責(zé)整個(gè)電腦的運(yùn)行調(diào)度。它是指揮者绒障,所以最底層的一些工作并不是由CPU來(lái)完成的吨凑。CPU以及高的速度再運(yùn)轉(zhuǎn),它的運(yùn)行是由一串串?dāng)?shù)字脈沖信號(hào)通過(guò)硅晶版上的晶體管實(shí)現(xiàn)的户辱,那一波波的數(shù)字脈沖信號(hào)震蕩的速度鸵钝,就是CPU那傳說(shuō)中的主頻。
CPU的主頻與CPU實(shí)際的運(yùn)算能力并沒有直接關(guān)系庐镐。如今的CPU工藝先進(jìn)恩商,運(yùn)算流水線短,其主頻的高低在一定意義上又可以體現(xiàn)CPU性能的高低必逆。CPU的主頻不代表CPU的速度怠堪,但提高主頻對(duì)于提高CPU運(yùn)算速度卻是至關(guān)重要的。
關(guān)于CPU使用率名眉,其實(shí)就是你運(yùn)行的程序占用的CPU資源粟矿,表示你的機(jī)器在某個(gè)時(shí)間點(diǎn)的運(yùn)行程序的情況。使用率越高损拢,說(shuō)明你的機(jī)器在這個(gè)時(shí)間上運(yùn)行了很多程序陌粹,反之較少。使用率的高低與你的CPU強(qiáng)弱有直接關(guān)系福压。現(xiàn)代分時(shí)多任務(wù)操作系統(tǒng)對(duì) CPU 都是分時(shí)間片使用的:比如A進(jìn)程占用10ms掏秩,然后B進(jìn)程占用30ms或舞,然后空閑60ms,再又是A進(jìn)程占10ms蒙幻,B進(jìn)程占30ms映凳,空閑60ms;如果在一段時(shí)間內(nèi)都是如此,那么這段時(shí)間內(nèi)的占用率為40%杆煞。CPU對(duì)線程的響應(yīng)并不是連續(xù)的魏宽,通常會(huì)在一段時(shí)間后自動(dòng)中斷線程腐泻。未響應(yīng)的線程增加决乎,就會(huì)不斷加大CPU的占用。
操作系統(tǒng)的設(shè)計(jì)派桩,可以歸結(jié)為三點(diǎn):
- (1)以多進(jìn)程形式构诚,允許多個(gè)任務(wù)同時(shí)運(yùn)行;
- (2)以多線程形式铆惑,允許單個(gè)任務(wù)分成不同的部分運(yùn)行范嘱;
- (3)提供協(xié)調(diào)機(jī)制,一方面防止進(jìn)程之間和線程之間產(chǎn)生沖突员魏,另一方面允許進(jìn)程之間和線程之間共享資源丑蛤。
CPU型號(hào) | CPU內(nèi)核信息 |
---|---|
I3 | 雙核四線程 |
I5 | 雙核四線程 |
I5 | 四核四線程 |
I7 | 四核八線程 |
I7 | 六核十二線程 |
關(guān)于多核、多處理器撕阎、多線程
了解了CPU的工作機(jī)制受裹,我們?cè)賮?lái)分析一下CPU的多核、多處理器虏束,與多線程棉饶。也許有人會(huì)問:“了解這些有什么卵用”,其實(shí)在我看來(lái)镇匀,詳細(xì)了解這些硬件對(duì)于我們理解多線程技術(shù)的必要性和開展多線程編程都是很必要的照藻,可以提供宏觀的理論依據(jù)。
多核
CPU的性能主要靠提高核心工作頻率來(lái)提高汗侵,由于物理限制幸缕,不能把CPU的核心頻率無(wú)限提高,所以發(fā)展出來(lái)雙核心或多核心的CPU晰韵。相當(dāng)于在一枚處理器上集成多個(gè)完整的計(jì)算引擎(內(nèi)核)冀值,他們共享緩存,內(nèi)存宫屠,寄存器等列疗。
核,是物理的浪蹂,幾核就是真的有幾個(gè)物理核心抵栈。線程就是英特爾的超線程技術(shù)告材。是在一個(gè)實(shí)體處理器中,提供兩個(gè)邏輯線程古劲。線程是虛擬的斥赋,不是真實(shí)存在的。但性能上产艾,會(huì)模擬真實(shí)的核疤剑。也就是說(shuō),雙核4線程闷堡,看起來(lái)很像4核隘膘,但比真實(shí)的4核4線程慢,卻比雙核雙線程快杠览。
手機(jī)多核其實(shí)應(yīng)該叫多CPU,將多個(gè)CPU芯片封裝起來(lái)處理不同的事情弯菊,你甚至可以戲稱為“膠水核心”,也就是被強(qiáng)行粘在一起的意思踱阿。在待機(jī)或者空閑的時(shí)候管钳,八核的手機(jī)也只能用到一到兩個(gè)核心。
而電腦則不同软舌,PC的多核處理器是指在一個(gè)處理器上集成了多個(gè)運(yùn)算核心才漆,通過(guò)相互配合、相互協(xié)作可以處理同一件事情佛点,是多個(gè)并行的個(gè)體封裝在了一起醇滥。用一句話概括,就是并行處理恋脚,雙核就是單車道變多車道
我們都知道智能手機(jī)都是有CPU的腺办,iPhone6使用的A8處理器是一款雙核處理器。
多處理器(多CPU)
多處理器系統(tǒng)是指包含兩臺(tái)或多臺(tái)功能相近的處理器(多CPU)糟描,處理器之間彼此可以交換數(shù)據(jù)怀喉,所有處理器共享內(nèi)存,I/O設(shè)備船响,控制器躬拢,及外部設(shè)備,整個(gè)硬件系統(tǒng)由統(tǒng)一的操作系統(tǒng)控制见间,在處理器和程序之間實(shí)現(xiàn)作業(yè)聊闯、任務(wù)、程序米诉、數(shù)組極其元素各級(jí)的全面并行菱蔬。目前主流的服務(wù)器架構(gòu),超級(jí)計(jì)算機(jī)等等,都是多CPU多核架構(gòu)拴泌。
多線程
多線程是為了使得多個(gè)線程并行的工作以完成多項(xiàng)任務(wù)魏身,以提高系統(tǒng)的效率。線程是在同一時(shí)間需要完成多項(xiàng)任務(wù)的時(shí)候被實(shí)現(xiàn)
的蚪腐。
多線程實(shí)現(xiàn)的相關(guān)討論
下面進(jìn)入到正餐了箭昵,在討論多線程之前,我們需要先認(rèn)識(shí)一下回季,進(jìn)程家制、線程,以及相關(guān)值得注意的問題泡一。
什么是線程颤殴、進(jìn)程
來(lái)來(lái)來(lái),先讀一個(gè)有趣的故事《進(jìn)程與線程的一個(gè)簡(jiǎn)單解釋》,淺顯易懂,生動(dòng)形象地解釋了多項(xiàng)成相關(guān)的很多典型問題瘾杭。通過(guò)上文我們大致可以宏觀了解這些問題了诅病。
進(jìn)程: 進(jìn)程是計(jì)算機(jī)中的程序關(guān)于某數(shù)據(jù)集合上的一次運(yùn)行活動(dòng)哪亿,是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位粥烁,是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ)。進(jìn)程是計(jì)算機(jī)中已運(yùn)行程序的實(shí)體蝇棉。其本身并不是幾部運(yùn)行單位讨阻,是線程的容器。
線程: 線程是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位篡殷。線程是一組指令的集合它被包含在進(jìn)程之中钝吮,是進(jìn)程中的實(shí)際運(yùn)作單位。一條線程指的是進(jìn)程中一個(gè)單一順序的控制流板辽,一個(gè)進(jìn)程中可以并發(fā)多個(gè)線程奇瘦,每條線程并行執(zhí)行不同的任務(wù)。線程是獨(dú)立調(diào)度和分派的基本單位劲弦。同一進(jìn)程中的多條線程將共享該進(jìn)程中的全部系統(tǒng)資源耳标,但是自有調(diào)用堆棧和寄存器環(huán)境。
線程邑跪、進(jìn)程的不同
主線程在程序中的地位和其他線程不同次坡,它是其他線程最終的父線程,且所有界面的顯示操作即AppKit或 UIKit的操作必須在主線程進(jìn)行画畅。
進(jìn)程和線程都是操作系統(tǒng)的概念砸琅。進(jìn)程是應(yīng)用程序的執(zhí)行實(shí)例,每個(gè)進(jìn)程是由私有的虛擬地址空間轴踱、代碼症脂、數(shù)據(jù)和其它各種系統(tǒng)資源組成。
線程和進(jìn)程十分相似,不同的只是線程比進(jìn)程小诱篷。首先沸版,線程采用了多個(gè)線程可共享資源的設(shè)計(jì)思想;例如兴蒸,它們的操作大部分都是在同一地址空間進(jìn)行的视粮。其次,從一個(gè)線程切換到另一線程所花費(fèi)的代價(jià)比進(jìn)程低橙凳。再次蕾殴,進(jìn)程本身的信息在內(nèi)存中占用的空間比線程大,因此線程更能允分地利用內(nèi)存岛啸。
線程是進(jìn)程的一部分
CPU調(diào)度的是線程
系統(tǒng)為進(jìn)程分配資源钓觉,不對(duì)線程分配資源
進(jìn)程和線程的關(guān)系:
一個(gè)線程只能屬于一個(gè)進(jìn)程,而一個(gè)進(jìn)程可以有多個(gè)線程坚踩,但至少有一個(gè)線程荡灾。 資源分配給進(jìn)程,同一進(jìn)程的所有線程共享該進(jìn)程的所有資源瞬铸。 處理機(jī)分給線程批幌,即真正在處理機(jī)上運(yùn)行的是線程。 線程在執(zhí)行過(guò)程中嗓节,需要協(xié)作同步荧缘。不同進(jìn)程的線程間要利用消息通信的辦法實(shí)現(xiàn)同步。
為什么要實(shí)現(xiàn)多線程
多線程技術(shù)的出現(xiàn)拦宣,主要是因?yàn)槎嗳蝿?wù)的需要截粗,比如我想同時(shí)寫文章和聽歌,如果我們的CPU一直被寫文章的任務(wù)占著鸵隧,等寫文章的任務(wù)結(jié)束后绸罗,再播放歌曲,很顯然達(dá)不到需要的“同時(shí)”做兩件事的效果豆瘫。
多線程的出現(xiàn)也是多核CPU珊蟀、多處理器計(jì)算機(jī)普及的需要,這樣可以提高CPU的利用率靡羡,增加并發(fā)性系洛,提高程序的執(zhí)行效率,更快的處理完任務(wù)略步。
在一些等待的任務(wù)實(shí)現(xiàn)上如用戶輸入描扯、文件讀寫和網(wǎng)絡(luò)收發(fā)數(shù)據(jù)等,線程就比較游泳了趟薄。在這種情況下我們可以釋放一些珍貴的資源如內(nèi)存占用等等绽诚。
多線程為何能實(shí)現(xiàn)
單就一個(gè)CPU而言兩個(gè)線程可以解決線程阻塞造成的不流暢問題,其本身運(yùn)行效率并沒有提高,多CPU的并行運(yùn)算才真正解決了運(yùn)行效率問題恩够,這也正是并發(fā)和并行的區(qū)別卒落。當(dāng)然,不管是多核還是單核開發(fā)人員不用過(guò)多的擔(dān)心蜂桶,因?yàn)槿蝿?wù)具體分配給幾個(gè)CPU運(yùn)算是由系統(tǒng)調(diào)度的儡毕,開發(fā)人員不用過(guò)多關(guān)心系統(tǒng)有幾個(gè)CPU。開發(fā)人員需要關(guān)心的是線程之間的依賴關(guān)系扑媚,因?yàn)橛行┎僮鞅仨氃谀硞€(gè)操作完成完才能執(zhí)行腰湾,如果不能保證這個(gè)順序勢(shì)必會(huì)造成程序問題。
每個(gè)線程被分配一個(gè)時(shí)間段疆股,稱作它的時(shí)間片费坊,即該進(jìn)程允許運(yùn)行的時(shí)間,使各個(gè)程序從表面上看是同時(shí)進(jìn)行的旬痹。如果在時(shí)間片結(jié)束時(shí)進(jìn)程還在運(yùn)行附井,則CPU將被剝奪并分配給另一個(gè)進(jìn)程。如果進(jìn)程在時(shí)間片結(jié)束前阻塞或結(jié)束两残,則CPU當(dāng)即進(jìn)行切換永毅。而不會(huì)造成CPU資源浪費(fèi)。在宏觀上:我們可以同時(shí)打開多個(gè)應(yīng)用程序磕昼,每個(gè)程序并行不悖卷雕,同時(shí)運(yùn)行节猿。但在微觀上:由于只有一個(gè)CPU票从,一次只能處理程序要求的一部分,如何處理公平滨嘱,一種方法就是引入時(shí)間片峰鄙,每個(gè)程序輪流執(zhí)行。調(diào)度程序所要做的就是維護(hù)一張就緒進(jìn)程列表太雨,當(dāng)進(jìn)程用完它的時(shí)間片后吟榴,它被移到隊(duì)列的末尾。
每個(gè)進(jìn)程都有私有的虛擬地址空間囊扳,進(jìn)程的所有線程共享同一地址空間吩翻。每個(gè)線程被CPU分配一個(gè)時(shí)間片,一旦被激活锥咸,它正常運(yùn)行直到時(shí)間片耗盡并被掛起狭瞎,此時(shí),操作系統(tǒng)選擇另一個(gè)線程進(jìn)行運(yùn)行搏予。通過(guò)時(shí)間片輪轉(zhuǎn)熊锭,又出于各個(gè)時(shí)間片很小(20毫秒級(jí)),看起來(lái)就像多個(gè)線程同時(shí)在工作碗殷。實(shí)際上精绎,只有在多處理器系統(tǒng)上才是真正的在可得到的處理器上同時(shí)運(yùn)行多個(gè)線程。
從一個(gè)進(jìn)程切換到另一個(gè)進(jìn)程是需要一定時(shí)間的--保存和裝入寄存器值及內(nèi)存映像锌妻,更新各種表格和隊(duì)列等代乃。假如進(jìn)程切換(process switch) - 有時(shí)稱為上下文切換(context switch),需要5毫秒仿粹,再假設(shè)時(shí)間片設(shè)為20毫秒襟己,則在做完20毫秒有用的工作之后,CPU將花費(fèi)5毫秒來(lái)進(jìn)行進(jìn)程切換牍陌。CPU時(shí)間的20%被浪費(fèi)在了管理開銷上擎浴。
時(shí)間片設(shè)得太短會(huì)導(dǎo)致過(guò)多的進(jìn)程切換,降低了CPU效率毒涧;而設(shè)得太長(zhǎng)又可能引起對(duì)短的交互請(qǐng)求的響應(yīng)變差贮预。將時(shí)間片設(shè)為100毫秒通常是一個(gè)比較合理的折衷。
線程越多越好嗎
線程多了可以提高程序并行執(zhí)行的速度契讲,但是并不是越多越好仿吞。
其一,每個(gè)線程都要占用內(nèi)存捡偏,多線程就意味著更多的內(nèi)存資源被占用唤冈,開啟線程需要占用一定的內(nèi)存空間(默認(rèn)情況下,主線程占用1M银伟,子線程占用512KB)你虹,如果開啟大量的線程,會(huì)占用大量的內(nèi)存空間彤避,降低程序的性能傅物。
其二,從微觀上講琉预,一個(gè)cpu不是同時(shí)執(zhí)行兩個(gè)線程的董饰,他是輪流執(zhí)行的,所以線程太多圆米,cpu必須不斷的在各個(gè)線程間快回更換執(zhí)行卒暂,線程間的切換無(wú)意間消耗了許多時(shí)間,所以cpu有效利用率反而是下降的
開發(fā)中實(shí)現(xiàn)多線程的方案
Mach是第一個(gè)以多線程方式處理任務(wù)的系統(tǒng)娄帖,因此多線程的底層實(shí)現(xiàn)機(jī)制是基于Mach的線程也祠。
然后開發(fā)中很少用Mach級(jí)的線程,因?yàn)镸ach級(jí)的線程沒有提供多線程的基本特征块茁,線程之間是獨(dú)立的
多線程的方案有以下幾種
- C語(yǔ)言的POSIX接口方案
Pthreads定義了一套C語(yǔ)言的類型齿坷、函數(shù)與常量桂肌,它以pthread.h頭文件和一個(gè)線程庫(kù)實(shí)現(xiàn)。線程庫(kù)實(shí)行了POSIX線程標(biāo)準(zhǔn)通常稱為Pthreads永淌。POSIX線程具有很好的可移植性崎场,使用pthreads編寫的代碼可運(yùn)行于Solaris、FreeBSD遂蛀、Linux 等平臺(tái)谭跨,Windows平臺(tái)亦有pthreads-win32可供使用。而且你需要手動(dòng)處理線程的各個(gè)狀態(tài)的轉(zhuǎn)換即管理生命周期李滴,比如螃宙,這段代碼雖然創(chuàng)建了一個(gè)線程,還需要銷毀這個(gè)線程所坯。感興趣的朋友谆扎,或者說(shuō)想要自己實(shí)現(xiàn)一套多線程方案,從底層開始定制芹助,那么可以去搜一下相關(guān)資料研究一下堂湖。
- OC的NSThread方案。是對(duì)POSIX thread的封裝
- C語(yǔ)言的GCD接口方案(性能最好状土,代碼更精簡(jiǎn))无蜂。
- OC的NSOperation和NSOperationQueue(基于GCD)方案。
小結(jié)
本文洋洋灑灑寫了好多看似跟多線程無(wú)關(guān)的東西蒙谓,其實(shí)我認(rèn)為這些對(duì)之后多線程的學(xué)習(xí)是有幫助的斥季,如果你認(rèn)真對(duì)了本文,相信你會(huì)對(duì)多線程有更深的理解累驮,作為多線程系列的開胃菜酣倾,本文到此就結(jié)束了,后續(xù)會(huì)陸續(xù)發(fā)布多線程相關(guān)的文章慰照,如有不對(duì)之處灶挟,還望觀看的朋友,在下面的評(píng)論區(qū)指出毒租,thanks.