Multi-Process(多行程)&Multi-Thread(多執行序)到底是個啥(1)
Multi-Process(多行程)&Multi-Thread(多執行序)到底是個啥(2)
Multi Thread (多執行序) 到底是個啥(3) 之 NodeJs 也有 threads
目前是仍在轉職階段,未來可能會往高併發或高流量的產業走,因此把有興趣的部分的筆記記錄下來。由於JS本身應用在Multi-Thread很少,也是在近幾年官方才公布node.js 可以有類似Multi-Thread的功能(Web版較早就有公布,不過應用似乎也較少),因此若筆記中有誤或講得不好的地方,歡迎打臉指正(我喜歡被打臉)。
一開始最讓人困惑就是Process 跟 Thread到底是個啥? 網路滿天飛的訊息真的霧裡看花。
我們想像一個生活中的情境:
有位很忙到翻掉的媽媽,要在下午三點前送出Email, 還要顧小孩,還要煮水、煎蛋,如果是我,我只能在煎蛋之餘煮水,等待煮水之餘再去打Email,等到一切平靜下來再來哄小孩。
這種一心多用的概念就類似電腦的Thread(執行序),實際上人也不可能一心多用,只是我們可以快速的一直切換想法,這邊做一下,那邊做一下,除非是連體嬰,不然應該是沒辦法同時想兩件事情。而電腦中的Thread也是如此,儘管有很多,但是實際上是快速的切換。
而Process就像是人類的大腦,可以掌管數個Thread來執行。每個人的大腦都不同,做的事情都不一樣,而一個社區可能有好幾位忙碌的媽媽或爸爸,每個人的目標、想法、要做的家事、工作、或是照顧的小孩都不一樣,我們就可以想像成數個不同的Process(行程)掌管無數個Thread在運行。而這群爸爸媽媽生活的社區,我們就可以想像成是一台容納很多Process 的電腦啦!
那實際上電腦到底是長什麼樣子的呢? 我們可以打開熟悉的工作管理員..裡面每一個應用程式其實就是Process,但這邊我們會注意到有些程式後面會有括弧寫數字,例如Google Chrome有62,而LOL只有3,這邊代表光Google Chrome 本身就開了62個Process,而LOL開3個,這邊直覺會想遊戲應該要比瀏覽器吃資源吧,為啥Chrome開這麼多,原來惡名昭彰的吃資源瀏覽器真不是蓋的...(Process 是會占用到記憶體的,啟動越多記憶體佔用就越大)
事實上Chrome吃資源是為了讓電腦運作更快,而不是沒來由的吃資源的,後面會再介紹官網對於瀏覽器Process的解釋。
看到這邊,想必仍然對Process、Thread非常抽象吧! 所以暫停一下,我們重新對名詞定義一下。
Process:
- 一個應用程式或是程式碼(Program)被執行後的狀態
- 會自動儲存相關的資料或是檔案到記憶體(stack, heap)
- 可以隨時被CPU執行
- 擁有一個或多個Thread(這點先留心中,我們記住thread是Process底下的執行單位就好)
Program:
咦? 剛剛看到一個新名詞,其實很好懂,這就是指我們寫好的程式碼,或是下載下來的應用程式,但是是在未執行的狀態。
Thread:
這就是每個Process底下會處理很多事情的執行序啦! 其中包含了:
- Stack: 程式碼執行時儲存運算過程需要的暫存資料(例如function、以及local variable等等)
- Register: 裡面儲存了目前Process運作的狀態紀錄,這是給CPU的資訊,可以告訴CPU目前Process運作到哪邊
OK,到這邊把簡單的名詞介紹完了,其實Process底層儲存的資料非常複雜,找機會再把讀到的筆記分享出來,我知道你一定還不懂這些東西到底在說啥,沒關係,我們只要記住一張圖就夠了。
把名詞介紹裡面結合成一張圖就是這樣囉! 下半部(register, stack, code)就是我們的thread裡面包含的資料,而整個大方框就是Process,不過我們這邊主要是看超人爸爸媽媽在電腦裡的運作方式,所以底層架構就記住這張圖就好啦,讓我們繼續看下去!
讓我們想像一下,在一個悠哉的下午,我打開我的電腦,啟動了兩個應用程式,第一個是我想聽音樂,因此啟動了Spotify,再來是我想要聊天,於是我打開FB Messenger。回顧一下剛剛說的,我啟動了兩個應用程式(Program),因而產生兩個Process,這下問題來了,我想要同時聽音樂又聊天,CPU要同時去運算兩個Process,這是不可能的(你心裡可能在想多核心,但我們先緩緩,先假設這是個單核心的時代)。偉大的作業系統在這邊就扮演了非常重要的角色。為了讓使用者有用起來真的像是在同時聽音樂和聊天的假象,作業系統讓我們的Spotify Process以及Messenger Process變成閃電俠,讓他們非常快速的不斷叫替作業。
舉例來說: Spotfiy 處理好一段音訊檔,把訊息傳給音效卡播音樂,趁這段空檔,快速切換到Messenger處理聊天的I/O,然後再快速切回Spotify處理音樂解析。這些切換模式都是底層演算法決定的。
歸功於電腦的超高速閃電俠運算,我們可以達到看似同時運作的假象,這種方式我們稱為Concurrency(併發多工)。什麼? 你說怎麼又有新名詞,沒錯,再來看一下新名詞吧。
Concurrency
以時間軸來看,總共三條時間軸,長方形為實際運作時間,沒有長方形代表沒有運作,所以這張圖可以得知,沒有任何一個時間點是有長方形重疊的。所以即便切換速度之快讓人有同步錯覺,本質終究不是同步運行的。那我如果任性,我就是要同步怎麼辦,當然沒問題。
Parallel
如其名,三條時間軸就像是三條平行時空同時運作,但是我們前面有提到,只有一個大腦是做不到這件事情的,因此這項任務就要交給多核心的CPU來做啦! 例如圖片中,有三條時間軸,就需要三個核心才能同時平行運做。
OK,認識了這兩個名詞之後,我們再回到剛剛的Process運作。其實我們剛剛已經不知不覺認識了Multi-Processing了。在維基百科中有提到
At the operating system level, multiprocessing is sometimes used to refer to the execution of multiple concurrent processes in a system, with each process running on a separate CPU or core, as opposed to a single process at any one instant.[6][7] When used with this definition, multiprocessing is sometimes contrasted with multitasking, which may use just a single processor but switch it in time slices between tasks (i.e. a time-sharing system).
大意是說,我們剛剛提到Spotify, Messenger的閃電俠模式也是multi-processing,很久以前的手機或電腦也是不支援Parallel的。不過在現代這種八核心基本配備的時代,Multi-Processing幾乎都是只Parallel運作方式了。因此我們再度回歸上面出現過的Process圖片。
Multi-Process
電腦平行運作(電腦是視情況做多核的 parallel,或是切換成 concurrency運算,由作業系統決定)三個Process,甚至是Spotify也可以叫出兩個,來個別分開處理不同功能,加快速度,甚至是可以在Core1的Spotify不幸當機關閉時,Core3還存在,可以繼續執行,並重啟本來Core1的任務。但這邊我們會發現一個問題,Spotify叫了兩個Process,因此data/files也複製了兩份,佔用了更多的空間,並且Core1、Core3要互通資源的話,I/O時間也是非常耗時的,因此如果只是單純要分工更細的話,可以採用Concurrency方式就夠快了,但是要省去耗時間的兇手I/O,以及占用記憶體的缺點,就可以使用Multi-Threading。
Multi-Threading
本來的Process裡面只有一根Thread,現在我們讓Thread增加,就像最一開始的例子,超級媽媽可以處理很多事情一樣。Thread可以分別處理不同的function,但是仍然保持data/files共享,可以減少I/O時間,另外每個Thread切換的速度也是比Process切換速度還快的,因為需載入或是寫入記憶體的資源也是比較小的。但這邊或許你已經想到,資源共享會產生一個大問題,就是race condition。控制Thread切換也是OS底層演算法控制,我們無法得知Concurrency是如何切換的。
例如我有5個Thread,我要他們都做一件事情(以下範例來自https://stackoverflow.com/questions/34510/what-is-a-race-condition)
int x = 0;
for ( int i = 0; i < 1000; i++ )
{
x = x + 1;
}
最終x不一定是5000。因為寫入機制是這樣:
取得x值
x += 1
儲存x值
實際Multi-Threading有可能是
Thread 1: 讀取x值 0
Thread 1: x += 1, x暫存為1
Thread 2: 讀取x值 0
Thread 2: x += 1, x暫存為1
Thread 2: 儲存x值,記憶體中為1
Thread 1: 儲存x值,記憶體中為1
由上可知,Thread 1 / Thread 2 做了一樣的事情,因為切換是無法控制的。
因此做好資料保護以及thread的schedule規劃一直是Multi-Threading的大課題,至於要怎麼控制呢? 打到這邊太累了,由下一章節再來做筆記吧!
目前為止簡單認識了Multi-Processing以及Multi-Threading基本概念,在重新認識一下一個Process啟動到CPU運作的流程吧!
最後做個簡單的總結:
Multi-Processing
- 每個Process是獨立的,其中一個不幸掛掉並不影響整體運作,穩定性佳
- 占用較多資源,以及較長的I/O時間
- 在多核CPU中,有可能進行 Parallel 運算
Multi-Thread
- 可以共享同一個Process底下的data/files,減少I/O溝通時間
- 會有Race condition,必須謹慎處理資料保護這件事情
- 在多核CPU中,也有可能進行 Parallel 運算
下一章節再來更深入討論Google以及Oracle官方文件的解釋,以及一些javascript / python的簡單案例吧!