天天看點

程序與線程【入門篇】

本博文隻對程序和線程做理論講解,先帶領各位小夥伴走進程序和線程的大門。

程序

-- 程序是一個具有一定獨立功能的應用程式關于某個資料集合上的一次運作活動。      -----------------  一個Application對應一個程序,應用程式是靜态的,程序是動态的。

-- 程序是線程的容器,每個程序至少包含一個線程;      ------------------ 程序與線程是一對多的關系。

-- 程序是作業系統進行資源配置設定和排程的最小機關,資源包括CPU、記憶體空間、磁盤IO等;

-- 每個程序都是互相獨立的,不能進行資源共享;

-- 程序分為系統程序和使用者程序,系統程序就是各個系統應用所啟動的程序,而系統應用是為了滿足作業系統本身各項功能的應用;使用者程序就是我們終端使用者啟動的程序,比如QQ、微信、Office辦公軟體等。

線程

-- 線程是CPU排程的最小機關,必須依賴于程序而存在;

-- 線程本身基本不擁有系統資源,隻擁有運作中必不可少的程式計數器、一組寄存器和棧,但線程之間可以共享同屬程序中的全部系統資源。

-- 線程無處不在,任何程式都必須建立線程,線程才是真正做事的(就像我們程式猿&媛一樣),在Java程式中,必須由main函數作為程式入門啟動主線程,在Android中進行網絡請求等耗時操作,我們必須開子線程,不能阻塞UI線程。

CPU核心數和線程數的關系

多核心

單晶片多處理器簡稱CMP(Chip Multiprocessors),也稱多核心處理器。是指在一個晶片上內建多個微處理器核心,各個處理器并行執行不同的程序。這種依靠多個CPU同時并行地運作程式是實作超高速計算的一個重要方向,稱為并行處理。

多線程

Simultaneous Multithreading,簡稱SMT。使得同一處理器上的多個線程同步執行并共享處理器的執行資源。

先前CPU是單核的,隻有一個線程,目前主流CPU都是多核的,增加核心數就是為了增加線程數,我們都知道作業系統并不能執行任務,真正執行任務的是線程,核心數越多,表明可以并行的線程數越多,執行任務效率就越高。一般情況下,核心數與線程數是1:1的關系,比如我們常見的四核CPU一般擁有4個線程,但Intel引入超線程技術後,使得核心數與線程數形成了1:2的關系,如圖1所示,4個核心對應8個邏輯處理器。

程式與線程【入門篇】

圖1

多核心與多CPU傻傻分不清楚

我剛開始也以為多核心和多CPU不是一回事,CPU是中央處理器,就跟我們中國隻有一個黨中央,每個國家隻有一個領袖人物一樣,但我忘記了最牛的上司都是無為而治,懂得分權和用人,凡事都親力親為的上司會累死,是以CPU也是如此,從外觀來看,我們的電腦或者筆記本确實隻有一個CPU,但是CPU内部又是由多個微處理組成,每一個微處理器就是一個核心,也就是一個微型CPU,如此來看,多核心可以了解為多CPU。

CPU時間片輪轉機制

細心的小夥伴可能發現了,在圖1中邏輯處理器隻有8個,卻有3865個線程,也就是說線程數遠超核心數,并不是1:2的關系,這不是和先前講的沖突了嗎?但是請你再細心一點,先前講的1:2的關系是建立在并行的前提下的,8個核心就是8條道路,可以滿足8個線程同時并行于這8條道路上。但我們又有疑問了,我們平時開發的時候開的軟體可不止8個,并沒有感覺到任何卡頓的情況,而且我們撸碼的時候,想啟動線程就啟動線程,不用顧忌那麼多事情,為什麼?這就得益于作業系統為我們提供的CPU時間片輪轉機制,也叫RR排程(Round-robin scheduling)。在RR排程算法中,将一個較小時間單元定義為時間量或時間片。時間片的大小通常為 10~100ms。就緒隊列作為循環隊列。CPU排程程式循環整個就緒隊列,為每個程序配置設定不超過一個時間片的CPU。

​​點選這裡檢視​​百度百科關于時間片輪轉機制的解釋

維基百科上關于RR排程有這樣一段解釋:

To schedule processes fairly, a round-robin scheduler generally employs time-sharing, giving each job a time slot or quantum[4] (its allowance of CPU time), and interrupting the job if it is not completed by then. The job is resumed next time a time slot is assigned to that process. If the process terminates or changes its state to waiting during its attributed time quantum, the scheduler selects the first process in the ready queue to execute. In the absence of time-sharing, or if the quanta were large relative to the sizes of the jobs, a process that produced large jobs would be favoured over other processes.

Round-robin algorithm is a pre-emptive algorithm as the scheduler forces the process out of the CPU once the time quota expires.

For example, if the time slot is 100 milliseconds, and job1 takes a total time of 250 ms to complete, the round-robin scheduler will suspend the job after 100 ms and give other jobs their time on the CPU. Once the other jobs have had their equal share (100 ms each), job1 will get another allocation of CPU time and the cycle will repeat. This process continues until the job finishes and needs no more time on the CPU.

ps:RR排程唯一有趣的一點是時間片的長度。從一個程序切換到另一個程序是需要定時間的,包括儲存和裝入寄存器值及記憶體映像,更新各種表格和隊列等。假設程序切換(也叫上下文切換)需要5ms,時間片設定為20ms,則在做完20ms有用的工作之後,CPU還得花費5ms進行程序切換,這樣25%的時間被浪費在了管理開銷上。為了提高CPU 效率,我們可以将時間片設為5000ms。這時浪費的時間隻有0.1%。但考慮到在一個分時系統中,如果有10 個互動使用者幾乎同時按下Enter鍵,将發生什麼情況?假設所有其他程序都用足它們的時間片的話,最後一個不幸的程序不得不等待5秒才獲得運作機會。多數使用者無法忍受一條簡短指令要5秒才能做出響應,同樣的問題在一台支援多道程式的個人計算機上也會發生。結論可以歸結如下:時間片設得太短會導緻程序頻繁切換,降低了CPU效率,而設得太長又可能引起對短的互動請求的響應變差。将時間片設為100ms通常是一個比較合理的折衷。

并發

指應用能夠交替執行不同的任務,比如單核CPU執行多線程并非是同時執行多個任務,而是以我們不可察覺的速度不斷去切換這些任務,以達到"同時執行效果"。當談論并發的時候一定要加個機關時間,也就是說機關時間内并發量是多少?離開了機關時間其實是沒有意義的。

并行

指應用能夠同時執行不同的任務,比如吃飯的時候可以邊吃飯邊訓熊孩子,這兩件事情可以同時執行。(吃飯的時候盡量别訓小孩,會影響胃消化食物)

高并發程式設計的好處和注意事項

高并發程式設計的好處

<1>充分利用CPU資源

目前市面的計算機都是多核CPU,如果你用的i3的CPU,最差的也是雙核四線程,而你隻用一個線程處理任務,那麼就浪費了3/4的CPU性能,這就好比你開三萬的月薪招了一個進階開發,卻給他配置設定三千月薪的開發實習生就能做的工作,明顯大材小用,浪費了公司資源。

<2>加快響應速度

我們在用百度雲或者迅雷下載下傳東西的時候,一般都是好多個任務一塊下載下傳,而不是一個一個去下載下傳,為什麼呢?快呀,古語有雲:三個臭皮匠賽過諸葛亮嘛~

<3>友善業務拆分

例如我們實作電商系統,下訂單和給使用者發送短信、郵件就可以進行拆分,将給使用者發送短信、郵件這兩個步驟獨立為單獨的子產品,并交給其他線程去執行。這樣既增加了異步的操作,提升了系統性能,又使程式子產品化,清晰化和簡單化。

注意事項

<1>線程之間的安全性

在同一個程序裡面的多線程是資源共享的,也就是都可以通路同一個記憶體位址當中的一個變量。若每個線程中對全局變量、靜态變量隻有讀操作,而無寫操作,一般來說這個全局變量是線程安全的;但如果多個線程同時執行寫操作,一般都需要考慮線程同步問題,否則就可能引入線程安全問題。

<2>線程之間的死鎖

為了解決線程之間的安全性引入了Java的鎖機制,而一不小心就會産生Java線程死鎖的多線程問題,因為不同的線程都在等待那些根本不可能被釋放的鎖,進而導緻所有的工作都無法完成。假設有兩個線程,分别代表兩個饑餓的人,他們必須共享刀叉輪流吃飯。他們都需要獲得兩個鎖:共享刀和共享叉的鎖,假如線程A 獲得了刀,而線程B 獲得了叉。線程A 就會進入阻塞狀态來等待獲得叉,而線程B 則阻塞來等待線程A 所擁有的刀。這隻是人為設計的例子,但盡管在運作時很難探測到,這類情況卻時常發生。

<3>伺服器資源被耗盡導緻當機

繼續閱讀