進程是程序執行時的一個實例,即它是程序已經執行到課中程度的數據結構的聚集。從內核的觀點看,進程的目的就是擔當分配系統資源(CPU時間、內存等)的基本單位。php
線程是進程的一個執行流,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位。一個進程由幾個線程組成(擁有不少相對獨立的執行流的用戶程序共享應用程序的大部分數據結構),線程與同屬一個進程的其餘的線程共享進程所擁有的所有資源。算法
"進程——資源分配的最小單位,線程——程序執行的最小單位"編程
進程有獨立的地址空間,一個進程崩潰後,在保護模式下不會對其它進程產生影響,而線程只是一個進程中的不一樣執行路徑。線程有本身的堆棧和局部變量,但線程沒有單獨的地址空間,一個線程死掉就等於整個進程死掉,因此多進程的程序要比多線程的程序健壯,但在進程切換時,耗費資源較大,效率要差一些。但對於一些要求同時進行而且又要共享某些變量的併發操做,只能用線程,不能用進程。瀏覽器
總的來講就是:進程有獨立的地址空間,線程沒有單獨的地址空間(同一進程內的線程共享進程的地址空間)。(下面的內容摘自Linux下的多線程編程)服務器
使用多線程的理由之一是和進程相比,它是一種很是"節儉"的多任務操做方式。咱們知道,在Linux系統下,啓動一個新的進程必須分配給它獨立的地址空間,創建衆多的數據表來維護它的代碼段、堆棧段和數據段,這是一種"昂貴"的多任務工做方式。而運行於一個進程中的多個線程,它們彼此之間使用相同的地址空間,共享大部分數據,啓動一個線程所花費的空間遠遠小於啓動一個進程所花費的空間,並且,線程間彼此切換所需的時間也遠遠小於進程間切換所須要的時間。據統計,總的說來,一個進程的開銷大約是一個線程開銷的30倍左右,固然,在具體的系統上,這個數據可能會有較大的區別。數據結構
使用多線程的理由之二是線程間方便的通訊機制。對不一樣進程來講,它們具備獨立的數據空間,要進行數據的傳遞只能經過通訊的方式進行,這種方式不只費時,並且很不方便。線程則否則,因爲同一進程下的線程之間共享數據空間,因此一個線程的數據能夠直接爲其它線程所用,這不只快捷,並且方便。固然,數據的共享也帶來其餘一些問題,有的變量不能同時被兩個線程所修改,有的子程序中聲明爲static的數據更有可能給多線程程序帶來災難性的打擊,這些正是編寫多線程程序時最須要注意的地方。多線程
除了以上所說的優勢外,不和進程比較,多線程程序做爲一種多任務、併發的工做方式,固然有如下的優勢:併發
線程共享的環境包括:進程代碼段、進程的公有數據(利用這些共享的數據,線程很容易的實現相互之間的通信)、進程打開的文件描述符、信號的處理器、進程的當前目錄和進程用戶ID與進程組ID。函數
進程擁有這許多共性的同時,還擁有本身的個性。有了這些個性,線程才能實現併發性。這些個性包括:spa
1.線程ID
每一個線程都有本身的線程ID,這個ID在本進程中是惟一的。進程用此來標
識線程。
2.寄存器組的值
因爲線程間是併發運行的,每一個線程有本身不一樣的運行線索,當從一個線
程切換到另外一個線程上 時,必須將原有的線程的寄存器集合的狀態保存,以便
未來該線程在被從新切換到時能得以恢復。
3.線程的堆棧
堆棧是保證線程獨立運行所必須的。
線程函數能夠調用函數,而被調用函數中又是能夠層層嵌套的,因此線程
必須擁有本身的函數堆棧, 使得函數調用能夠正常執行,不受其餘線程的影
響。
4.錯誤返回碼
因爲同一個進程中有不少個線程在同時運行,可能某個線程進行系統調用
後設置了errno值,而在該 線程尚未處理這個錯誤,另一個線程就在此時
被調度器投入運行,這樣錯誤值就有可能被修改。
因此,不一樣的線程應該擁有本身的錯誤返回碼變量。
5.線程的信號屏蔽碼
因爲每一個線程所感興趣的信號不一樣,因此線程的信號屏蔽碼應該由線程自
己管理。但全部的線程都 共享一樣的信號處理器。
6.線程的優先級
因爲線程須要像進程那樣可以被調度,那麼就必需要有可供調度使用的參
數,這個參數就是線程的 優先級。
Nginx 是非阻塞IO & IO複用模型,經過操做系統提供的相似 epoll 的功能,能夠在一個線程裏處理多個客戶端的請求。
Nginx 的進程就是線程,即每一個進程裏只有一個線程,但這一個線程能夠服務多個客戶端。
PHP-FPM 是阻塞的單線程模型,pm.max_children 指定的是最大的進程數量,pm.max_requests 指定的是每一個進程處理多少個請求後重啓(由於 PHP 偶爾會有內存泄漏,因此須要重啓).
PHP-FPM 的每一個進程也只有一個線程,可是一個進程同時只能服務一個客戶端。
Linux 下相對來講建立多進程的開銷比較小(寫時複製,但也比建立多線程昂貴),而 Linux 的線程功能又不是很強大。使用進程主要是由於採用非阻塞與I/O複用,能夠帶來比多線程更高的效率,可是代碼邏輯會更復雜(參考UNPv1)。
可是有的狀況,好比瀏覽器若是也所有使用多進程技術,那麼進程數會特別多,這時須要線程進程協做方式,好比chromium瀏覽器:http://blog.csdn.net/talking12391239/article/details/19755997
什麼時候選用多進程,多線程呢,猶以下經驗:
1)須要頻繁建立銷燬的優先用線程
緣由請看上面的對比。
這種原則最多見的應用就是Web服務器了,來一個鏈接創建一個線程,斷了就銷燬線程,要是用進程,建立和銷燬的代價是很難承受的
2)須要進行大量計算的優先使用線程
所謂大量計算,固然就是要耗費不少CPU,切換頻繁了,這種狀況下線程是最合適的。
這種原則最多見的是圖像處理、算法處理。
3)強相關的處理用線程,弱相關的處理用進程
什麼叫強相關、弱相關?理論上很難定義,給個簡單的例子就明白了。
一 般的Server須要完成以下任務:消息收發、消息處理。「消息收發」和「消息處理」就是弱相關的任務,而「消息處理」裏面可能又分爲「消息解碼」、「業 務處理」,這兩個任務相對來講相關性就要強多了。所以「消息收發」和「消息處理」能夠分進程設計,「消息解碼」、「業務處理」能夠分線程設計。
固然這種劃分方式不是一成不變的,也能夠根據實際狀況進行調整。
4)可能要擴展到多機分佈的用進程,多核分佈的用線程
緣由請看上面對比。
5)都知足需求的狀況下,用你最熟悉、最拿手的方式
至於「數據共享、同步」、「編程、調試」、「可靠性」這幾個維度的所謂的「複雜、簡單」應該怎麼取捨,沒有明確的選擇方法。但能夠根據一個選擇原則:若是多進程和多線程都可以知足要求,那麼選擇最熟悉、最拿手的那個。
須要提醒的是:雖然給了這麼多的選擇原則,但實際應用中基本上都是「進程+線程」的結合方式,千萬不要真的陷入一種非此即彼的誤區。