執行緒和程序的比較
在理解程序和執行緒概念之前首選要對併發有一定的感性認識,如果伺服器同一時間內只能服務於一個客戶端,其他客戶端都再那裡傻等的話,可見其效能的低下估計會被客戶罵出翔來,因此併發程式設計應運而生,併發是網路程式設計中必須考慮的問題。實現併發的方式有多種:比如多程序、多執行緒、IO多路複用。
多程序
程序是資源(CPU、記憶體等)分配的基本單位,它是程式執行時的一個例項。程式執行時系統就會建立一個程序,併為它分配資源,然後把該程序放入程序就緒佇列,程序排程器選中它的時候就會為它分配CPU時間,程式開始真正執行。
Linux系統函式fork()
可以在父程序中建立一個子程序,這樣的話,在一個程序接到來自客戶端新的請求時就可以複製出一個子程序讓其來處理,父程序只需負責監控請求的到來,然後建立子程序讓其去處理,這樣就能做到併發處理。
# -*- coding:utf-8 -*-
import os
print('當前程序:%s 啟動中 ....' % os.getpid())
pid = os.fork()
if pid == 0:
print('子程序:%s,父程序是:%s' % (os.getpid(), os.getppid()))
else:
print('程序:%s 建立了子程序:%s' % (os.getpid(),pid ))
輸出結果:
當前程序:27223 啟動中 ....
程序:27223 建立了子程序:27224
子程序:27224,父程序是:27223
fork函式會返回兩次結果,因為作業系統會把當前程序的資料複製一遍,然後程式就分兩個程序繼續執行後面的程式碼,fork分別在父程序和子程序中返回,在子程序返回的值pid永遠是0,在父程序返回的是子程序的程序id。
多執行緒
執行緒是程式執行時的最小單位,它是程序的一個執行流,是CPU排程和分派的基本單位,一個程序可以由很多個執行緒組成,執行緒間共享程序的所有資源,每個執行緒有自己的堆疊和區域性變數。執行緒由CPU獨立排程執行,在多CPU環境下就允許多個執行緒同時執行。同樣多執行緒也可以實現併發操作,每個請求分配一個執行緒來處理。
執行緒和程序各自有什麼區別和優劣呢?
-
程序是資源分配的最小單位,執行緒是程式執行的最小單位。
-
程序有自己的獨立地址空間,每啟動一個程序,系統就會為它分配地址空間,建立資料表來維護程式碼段、堆疊段和資料段,這種操作非常昂貴。而執行緒是共享程序中的資料的,使用相同的地址空間,因此CPU切換一個執行緒的花費遠比程序要小很多,同時建立一個執行緒的開銷也比程序要小很多。
-
執行緒之間的通訊更方便,同一程序下的執行緒共享全域性變數、靜態變數等資料,而程序之間的通訊需要以通訊的方式(IPC)進行。不過如何處理好同步與互斥是編寫多執行緒程式的難點。
-
但是多程序程式更健壯,多執行緒程式只要有一個執行緒死掉,整個程序也死掉了,而一個程序死掉並不會對另外一個程序造成影響,因為程序有自己獨立的地址空間。
老外的原話是這麼說的 —-《Unix網路程式設計》:
fork is expensive. Memory is copied from the parent to the child, all descriptors are duplicated in the child, and so on. Current implementations use a technique called copy-on-write, which avoids a copy of the parent’s data space to the child until the child needs its own copy. But, regardless of this optimization, fork is expensive.
IPC is required to pass information between the parent and child after the fork. Passing information from the parent to the child before the fork is easy, since the child starts with a copy of the parent’s data space and with a copy of all the parent’s descriptors. But, returning information from the child to the parent takes more work.
Threads help with both problems. Threads are sometimes called lightweight processes since a thread is “lighter weight” than a process. That is, thread creation can be 10–100 times faster than process creation.
All threads within a process share the same global memory. This makes the sharing of information easy between the threads, but along with this simplicity comes the problem