what?
進程和線程的概念:
進程是資源佔用的最小單位
線程是內核調度執行的最小單位
進程和線程的主要區別:
進程之間是彼此獨立的,由master進程通過fork()系統調用派生子進程
線程是共享內存空間的,主線程派生子線程
why?
進程和線程的優缺點:
進程:
優點:進程由於各自有獨立的內存空間,所以更加穩定,子進程之間不受影響,但是主進程崩潰會導致全局,而且在python中不受GIL(全局解釋器鎖)限制,可以充分利用多核cpu
缺點:對於內存資源佔用比較高,而且創建一個進程的代價比線程要大
線程:
優點:由於共享內存空間,所以資源佔用比較小,並且創建的代價小於進程,在python中受到GIL的限制,導致只能使用一個cpu核心,所以某一時刻運行的線程只有一個
缺點:由於共享內存空間也導致了缺點,資源徵用的問題(python中可以通過鎖的機制限制),並且一個線程的崩潰可能導致整個進程崩潰
fork()系統調用:
是unix/linux上比較特殊的一個系統調用,用於創建子進程,其特殊之處在於其他的系統調用函數一般調用一次返回一次,fork()調用一個返回兩次(父進程pid+子進程pid),且fork()調用時返回的子進程pid永遠爲0
where?(python中考慮)
多進程和多線程的共同目標是實現多任務
任務類型:cpu密集型和io密集型
cpu密集型:應該使用多進程,充分利用多核cpu實現真正意義上的併發執行
io密集型:可以使用多線程,節約資源
how?
在python中怎樣使用多進程和多線程編程?
多線程
python對於多線程的支持提供了兩個基礎庫,較爲底層的thread模塊和較爲高層的threading模塊
實現原理:
將準備併發執行的代碼當做參數傳遞給threading.Thread()創建一個線程對象,結合程序控制結構(循環)等方式來完成此線程對象start()的多次調用,從而實現多線程
示例代碼:(利用多線程實現併發socket通信服務端)
import threading ##導入線程庫
import socket ##導入socket
s=socket.socket() #創建socket對象
s.bind(('0.0.0.0',8888)) #綁定套接字
s.listen(10) #監聽套接字
def run(): #定義處理函數
sock,addr=s.accept()
while True:
a=sock.recv(1024)
if a:
sock.send(a.upper())
else:
sock.close()
break
if __name__ =='__main__':
for i in xrange(20): #根據for循環創建20個線程
t=threading.Thread(target=run) #創建線程對象
t.start() #運行線程
此示例的第二種寫法:
import threading ##導入線程庫
import socket ##導入socket
s=socket.socket() #創建socket對象
s.bind(('0.0.0.0',8888)) #綁定套接字
s.listen(10) #監聽套接字
class Mythread(threading.Thread):
def run(self): #定義處理函數
sock,addr=s.accept()
while True:
a=sock.recv(1024)
if a:
sock.send(a.upper())
else:
sock.close()
break
if __name__ =='__main__':
for i in xrange(20): #根據for循環創建20個線程
t=Mythread() #創建線程對象
t.start() #運行線程
2.多進程
python提供可multiprocessing模塊中的Process類來創建進程對象,同時該模塊還提供了Pool類來創建進程池對象,以及Queue和Pipe實現進程間通信
實現原理:
將準備併發執行的代碼當做參數傳遞給multiprocessing.Process()創建一個進程對象,結合程序控制結構(循環)等方式來完成此進程對象start()的多次調用,從而實現多進程
示例代碼:(利用多進程實現併發socket通信服務端)
import multiprocessing ##導入線程庫
import socket ##導入socket
s=socket.socket() #創建socket對象
s.bind(('0.0.0.0',8888)) #綁定套接字
s.listen(10) #監聽套接字
def run(): #定義處理函數
sock,addr=s.accept()
while True:
a=sock.recv(1024)
if a:
sock.send(a.upper())
else:
sock.close()
break
if __name__ =='__main__':
for i in xrange(20): #根據for循環創建20個線程
t=multiprocess.Process(target=run) #創建線程對象
t.start() #運行線程
//可以使用ps aux | grep python 查看已經運行了20個進程
同上:也可以自定義類並繼承Process類再實例化對象的方式進行編寫
總結:對於多任務的情形,併發是不可避免的問題,多進程和多線程可以實現併發,但是由於其都有不可避免的缺陷,所以如何讓單進程或單線程實現併發任務的處理,如nginx,就需要使用異步IO的機制,基於事件驅動,在python中實現此機制的稱爲協程。