Python 中進程、線程、協程、同步、異步、回調

上下文切換,指的是程序在執行中的一個狀態。通常我們會用調用棧來表示這個狀態——棧記載了每個調用層級執行到哪裏,還有執行時的環境情況等所有有關的信息
1.進程
每個進程有獨立的地址空間,資源句柄,他們互相之間不發生干擾。每個進程在內核中會有一個數據結構進行描述,我們稱其爲進程描述符。這些描述符包含了系統管理進程所需的信息,並且放在一個叫做任務隊列的隊列裏面。
進程的狀態:就緒態,運行態,睡眠態。就緒和執行可以互相轉換,基本這就是調度的過程。而當執行態程序需要等待某些條件(最典型就是IO)時,就會陷入睡眠態。而條件達成後,一般會自動進入就緒
阻塞: 當進程需要在某個文件句柄上做IO,這個fd又沒有數據給他的時候,就會發生阻塞

2.線程
線程是一種輕量進程,實際上在linux內核中,兩者幾乎沒有差別,除了一點——線程並不產生新的地址空間和資源描述符表,而是複用父進程的。但是無論如何,線程的調度和進程一樣,必須陷入內核態。
進程模型:爲每個客戶分配一個進程。優點是業務隔離,在一個進程中出現的錯誤不至於影響整個系統,甚至其他進程.缺點是進程的分配和釋放有非常高的成本
線程模型: 爲每客戶分配一個線程。優點是更輕量,建立和釋放速度更快,而且多個上下文間的通訊速度非常快。缺點是一個線程出現問題容易將整個系統搞崩潰
setDaemon(True) 將線程聲明爲守護線程,必須在start() 方法調用之前設置,如果不設置爲守護線程程序會被無限掛起
線程方法:
for t in threads:
t.start() 激活線程,
t.getName() 獲取線程的名稱
t.setName() 設置線程的名稱
t.name 獲取或設置線程的名稱
t.is_alive() 判斷線程是否爲激活狀態
t.isAlive() 判斷線程是否爲激活狀態
t.setDaemon() 設置爲後臺線程或前臺線程(默認:False);通過一個布爾值設置線程是否爲守護線程,必須在執行start()方法之後纔可以使用。如果是後臺線程,主線程執行過程中,後臺線程也在進行,主線程執行完畢後,後臺線程不論成功與否,均停止;如果是前臺線程,主線程執行過程中,前臺線程也在進行,主線程執行完畢後,等待前臺線程也執行完成後,程序停止
t.isDaemon() 判斷是否爲守護線程
t.ident 獲取線程的標識符。線程標識符是一個非零整數,只有在調用了start()方法之後該屬性纔有效,否則它只返回None。
t.join() 逐個執行每個線程,執行完畢後繼續往下執行,該方法使得多線程變得無意義
t.run() 線程被cpu調度後自動執行線程對象的run方法
線程同步
鎖機制: threadLock = threading.Lock()
threadLock.acquire() 獲取鎖,可選的timeout參數不填時將一直阻塞直到獲得鎖定
threadLock.release() 釋放鎖
Queue模塊中的常用方法:
import Queue
Queue.qsize() 返回隊列的大小
Queue.empty() 如果隊列爲空,返回True,反之False
Queue.full() 如果隊列滿了,返回True,反之False
Queue.full 與 maxsize 大小對應
Queue.get([block[, timeout]]) 獲取隊列,timeout是等待時間
Queue.get_nowait() 相當Queue.get(False)
Queue.put(item) 寫入隊列,timeout是等待時間
Queue.put_nowait(item) 相當Queue.put(item, False)
Queue.task_done() 在完成一項工作之後,Queue.task_done()函數向任務已經完成的隊列發送一個信號
Queue.join() 實際上意味着等到隊列爲空,再執行別的操作
multiprocessing 模塊下的Pool類下的幾個方法:
apply(func[, args[, kwds]]) :使用arg和kwds參數調用func函數,結果返回前會一直阻塞,
由於這個原因,apply_async()更適合併發執行,另外,func函數僅被pool中的一個進程運行。
apply_async(func[, args[, kwds[, callback[, error_callback]]]]) :
apply()方法的一個變體,會返回一個結果對象。
如果callback被指定,那麼callback可以接收一個參數然後被調用,當結果準備好回調時會調用callback,
調用失敗時,則用error_callback替換callback。 Callbacks應被立即完成,否則處理結果的線程會被阻塞。
close() : 阻止更多的任務提交到pool,待任務完成後,工作進程會退出。
terminate() :不管任務是否完成,立即停止工作進程。在對pool對象進程垃圾回收的時候,會立即調用terminate()。
join() : wait工作線程的退出,在調用join()前,必須調用close() or terminate()。
這樣是因爲被終止的進程需要被父進程調用wait(join等價與wait),否則進程會成爲殭屍進程。
apply_async(func,args) 從進程池中取出一個進程執行func,args爲func的參數。它將返回一個AsyncResult的對象,你可以對該對象調用get()方法以獲得結果
map(func, iterable[, chunksize])
map_async(func, iterable[, chunksize[, callback[, error_callback]]])
imap(func, iterable[, chunksize])
imap_unordered(func, iterable[, chunksize])
starmap(func, iterable[, chunksize])
starmap_async(func, iterable[, chunksize[, callback[, error_back]]])
pool = Pool(5)
for i in range(1, 10):
pool.apply_async(func=f1, args=(i,), callback=f2) f1的return 結果傳遞給f2進行處理
pool.close()
pool.join()

pool = Pool(5) #創建擁有5個進程數量的進程池
#testFL:要處理的數據列表,run:處理testFL列表中數據的函數
rl =pool.map(run, testFL) 和map()函數一樣的原理
pool.close()#關閉進程池,不再接受新的進程
pool.join()#主進程阻塞等待子進程的退出


爲什麼python裏推薦用多進程而不是多線程,但是多進程也有其自己的限制:相比線程更加笨重、切換耗時更長,並且在python的多進程下,進程數量不推薦超過CPU核心數(一個進程只有一個GIL,所以一個進程只能跑滿一個CPU),因爲一個進程佔用一個CPU時能充分利用機器的性能,但是進程多了就會出現頻繁的進程切換,反而得不償失。不過特殊情況(特指IO密集型任務)下,多線程是比多進程好用的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章