在看thinking in java 的 併發 章節時,裏面有這樣一句話:實現併發的最簡單的方式就是多進程,但沒有進一步的解釋說明,而後後面都在講多線程編程,當時就有疑惑,那到底多進程和多線程該如何選擇,html
網上找答案時,發現這篇文章總結的比較到位,遂轉來分享學習。完整的原文包括一些簡單的數據測試,具體能夠看原博客。java
-----------------------------------------------------------------------------------算法
轉自:http://blog.csdn.net/lishenglong666/article/details/8557215編程
魚仍是熊掌:淺談多進程多線程的選擇服務器
關於多進程和多線程,教科書上最經典的一句話是「進程是資源分配的最小單位,線程是CPU調度的最小單位」,這句話應付考試基本上夠了,但若是在工做中遇到相似的選擇問題,那就沒有這麼簡單了,選的很差,會讓你深受其害。網絡
常常在網絡上看到有的XDJM問「多進程好仍是多線程好?」、「Linux下用多進程仍是多線程?」等等指望一勞永逸的問題,我只能說:沒有最好,只有更好。根據實際狀況來判斷,哪一個更加合適就是哪一個好。數據結構
咱們按照多個不一樣的維度,來看看多線程和多進程的對比(注:由於是感性的比較,所以都是相對的,不是說一個好得不得了,另一個差的沒法忍受)。多線程
對比維度併發 |
多進程分佈式 |
多線程 |
總結 |
數據共享、同步 |
數據共享複雜,須要用IPC;數據是分開的,同步簡單 |
由於共享進程數據,數據共享簡單,但也是由於這個緣由致使同步複雜 |
各有優點 |
內存、CPU |
佔用內存多,切換複雜,CPU利用率低 |
佔用內存少,切換簡單,CPU利用率高 |
線程佔優 |
建立銷燬、切換 |
建立銷燬、切換複雜,速度慢 |
建立銷燬、切換簡單,速度很快 |
線程佔優 |
編程、調試 |
編程簡單,調試簡單 |
編程複雜,調試複雜 |
進程佔優 |
可靠性 |
進程間不會互相影響 |
一個線程掛掉將致使整個進程掛掉 |
進程佔優 |
分佈式 |
適應於多核、多機分佈式;若是一臺機器不夠,擴展到多臺機器比較簡單 |
適應於多核分佈式 |
進程佔優 |
看起來比較簡單,優點對比上是「線程 3.5 v 2.5 進程」,咱們只管選線程就是了?
呵呵,有這麼簡單我就不用在這裏浪費口舌了,仍是那句話,沒有絕對的好與壞,只有哪一個更加合適的問題。咱們來看實際應用中究竟如何判斷更加合適。
1)須要頻繁建立銷燬的優先用線程
緣由請看上面的對比。
這種原則最多見的應用就是Web服務器了,來一個鏈接創建一個線程,斷了就銷燬線程,要是用進程,建立和銷燬的代價是很難承受的
2)須要進行大量計算的優先使用線程
所謂大量計算,固然就是要耗費不少CPU,切換頻繁了,這種狀況下線程是最合適的。
這種原則最多見的是圖像處理、算法處理。
3)強相關的處理用線程,弱相關的處理用進程
什麼叫強相關、弱相關?理論上很難定義,給個簡單的例子就明白了。
通常的Server須要完成以下任務:消息收發、消息處理。「消息收發」和「消息處理」就是弱相關的任務,而「消息處理」裏面可能又分爲「消息解碼」、「業務處理」,這兩個任務相對來講相關性就要強多了。所以「消息收發」和「消息處理」能夠分進程設計,「消息解碼」、「業務處理」能夠分線程設計。
固然這種劃分方式不是一成不變的,也能夠根據實際狀況進行調整。
4)可能要擴展到多機分佈的用進程,多核分佈的用線程
緣由請看上面對比。
5)都知足需求的狀況下,用你最熟悉、最拿手的方式
至於「數據共享、同步」、「編程、調試」、「可靠性」這幾個維度的所謂的「複雜、簡單」應該怎麼取捨,我只能說:沒有明確的選擇方法。但我能夠告訴你一個選擇原則:若是多進程和多線程都可以知足要求,那麼選擇你最熟悉、最拿手的那個。
須要提醒的是:雖然我給了這麼多的選擇原則,但實際應用中基本上都是「進程+線程」的結合方式,千萬不要真的陷入一種非此即彼的誤區。
進程是程序執行時的一個實例,即它是程序已經執行到課中程度的數據結構的聚集。從內核的觀點看,進程的目的就是擔當分配系統資源(CPU時間、內存等)的基本單位。
線程是進程的一個執行流,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位。一個進程由幾個線程組成(擁有不少相對獨立的執行流的用戶程序共享應用程序的大部分數據結構),線程與同屬一個進程的其餘的線程共享進程所擁有的所有資源。
"進程——資源分配的最小單位,線程——程序執行的最小單位"
進程有獨立的地址空間,一個進程崩潰後,在保護模式下不會對其它進程產生影響,而線程只是一個進程中的不一樣執行路徑。線程有本身的堆棧和局部變量,但線程沒有單獨的地址空間,一個線程死掉就等於整個進程死掉,因此多進程的程序要比多線程的程序健壯,但在進程切換時,耗費資源較大,效率要差一些。但對於一些要求同時進行而且又要共享某些變量的併發操做,只能用線程,不能用進程。
總的來講就是:進程有獨立的地址空間,線程沒有單獨的地址空間(同一進程內的線程共享進程的地址空間)。(下面的內容摘自Linux下的多線程編程)
使用多線程的理由之一是和進程相比,它是一種很是"節儉"的多任務操做方式。咱們知道,在Linux系統下,啓動一個新的進程必須分配給它獨立的地址空間,創建衆多的數據表來維護它的代碼段、堆棧段和數據段,這是一種"昂貴"的多任務工做方式。而運行於一個進程中的多個線程,它們彼此之間使用相同的地址空間,共享大部分數據,啓動一個線程所花費的空間遠遠小於啓動一個進程所花費的空間,並且,線程間彼此切換所需的時間也遠遠小於進程間切換所須要的時間。據統計,總的說來,一個進程的開銷大約是一個線程開銷的30倍左右,固然,在具體的系統上,這個數據可能會有較大的區別。
使用多線程的理由之二是線程間方便的通訊機制。對不一樣進程來講,它們具備獨立的數據空間,要進行數據的傳遞只能經過通訊的方式進行,這種方式不只費時,並且很不方便。線程則否則,因爲同一進程下的線程之間共享數據空間,因此一個線程的數據能夠直接爲其它線程所用,這不只快捷,並且方便。固然,數據的共享也帶來其餘一些問題,有的變量不能同時被兩個線程所修改,有的子程序中聲明爲static的數據更有可能給多線程程序帶來災難性的打擊,這些正是編寫多線程程序時最須要注意的地方。
除了以上所說的優勢外,不和進程比較,多線程程序做爲一種多任務、併發的工做方式,固然有如下的優勢:
在Unix上編程採用多線程仍是多進程的爭執由來已久,這種爭執最多見到在B/S通信中服務端併發技術 的選型上,好比WEB服務器技術中,Apache是採用多進程的(perfork模式,每客戶鏈接對應一個進程,每進程中只存在惟一一個執行線 程),Java的Web容器Tomcat、Websphere等都是多線程的(每客戶鏈接對應一個線程,全部線程都在一個進程中)。
從Unix發展歷史看,伴隨着Unix的誕生多進程就出現了,而多線程很晚才被系統支持,例如Linux直到內核2.6,才支持符合Posix規範的NPTL線程庫。進程和線程的特色,也就是各自的優缺點以下:
進程優勢:編程、調試簡單,可靠性較高。
進程缺點:建立、銷燬、切換速度慢,內存、資源佔用大。
線程優勢:建立、銷燬、切換速度快,內存、資源佔用小。
線程缺點:編程、調試複雜,可靠性較差。
上面的對比能夠歸結爲一句話:「線程快而進程可靠性高」。線程有個別名叫「輕量級進程」,在有的書籍資料上介紹線程能夠十倍、百倍的效率快於進程; 而進程之間不共享數據,沒有鎖問題,結構簡單,一個進程崩潰不像線程那樣影響全局,所以比較可靠。我相信這個觀點能夠被大部分人所接受,由於和咱們所接受的知識概念是相符的。
在寫這篇文章前,我也屬於這「大部分人」,這兩年在用C語言編寫的幾個C/S通信程序中,因時間緊老是採用多進程併發技術,並且是比較簡單的現場爲 每客戶fork()一個進程,當時老是擔憂併發量增大時負荷可否承受,盤算着等時間充裕了將它改成多線程形式,或者改成預先建立進程的形式,直到最近在網 上看到了一篇論文《Linux系統下多線程與多進程性能分析》做者「周麗 焦程波 蘭巨龍」,才認真思考這個問題,我本身也作了實驗,結論和論文做者的類似,但對大部分人能夠說是顛覆性的。