MultiProcess-MultiThread
聽到一些關于python多進程與多線的例子,感覺比較經典,把一些例子分享一下.
內容如下:
? ? Process、Thread、GIL、Process fork、Multiprocessing、Queue、ProcessPool、Multiprocess-Multithread comparison
(1) Process : 程序的一次執行(程序編寫完畢后代碼裝載入內存,系統分配資源運行)。每個進程有自己的內存空間、數據棧等,只能使用進 程間通訊,而不能直接共享信息?
(2) Thread線程:所有線程運行在同一個進程中,共享相同的運行環境。 每個獨立的線程有一個程序運行的入口、順序執行序列和程序的出口; 線程的運行可以被搶占(中斷),或暫時被掛起 (睡眠),讓其他線程運行(讓步);一個進程中的各個線程間共享同一片數據空間?
(3) 全局解釋器鎖GIL?
? ? GIL全稱全局解釋器鎖Global Interpreter Lock,GIL并不是Python的特性,它是在實現Python解析器(CPython)時 所引入的一個概念。?
? ? GIL是一把全局排他鎖,同一時刻只有一個線程在運行。 毫無疑問全局鎖的存在會對多線程的效率有不小影響。甚至就幾乎等于Python是個單線程的程序。?
? ? multiprocessing庫的出現很大程度上是為了彌補thread庫因為 GIL而低效的缺陷。它完整的復制了一套thread所提供的接口方便遷移。唯一的不同就是它使用了多進程而不是多線程。每個進程有自己的獨立的GIL,因此也不會出現進程之間的GIL爭搶。?
多線程處理的例子:
from?threading?import?Thread import?time def?my_counter():i?=?0for?_?in?range(100000000):i?=i+1return?True def?main():thread_array?=?{}start_time?=?time.time()for?tid?in?range(2):t?=?Thread(target=my_counter())t.start()t.join()#以單線程、阻塞的方式順序運行兩次my_counter函數end_time?=?time.time()print("Total?time:{}").format(end_time?-?start_time)if?__name__=="__main__":main()執行結果如下:
Total time:12.7875118256
執行結果如下:
Total time:15.8216409683
上述兩個例子的結果發現:單線程運行兩次函數的時間 ? 要比 ? 兩個線程同時運行函數的時間短(僅限于本例)。
(4) fork操作:?
調用一次,返回兩次。因為操作系統自動把當前進程(稱為父 進程)復制了一份(稱為子進程),然后分別在父進程和子進 程內返回。子進程永遠返回0,而父進程返回子進程的ID。子 進程只需要調用getppid()就可以拿到父進程的ID。
例:
執行結果如下:
Process (16480) start ...
I (16480) just created a child process (16481).
I am child process (16481) and my parent is (16480)
(5) multiprocessing是跨平臺版本的多進程模塊,它提供了一個Process類來代表一個進程對象,下面是示例代碼:?
from?multiprocessing?import?Process import?time def?f(n):time.sleep(1)print?n*nif?__name__=="__main__":for?i?in?range(10):p=Process(target=f,args=[i,])p.start()#使用多進程并發的方式執行函數f這個程序如果用單進程寫則需要執行10秒以上的時間, 而用多進程則啟動10個進程并行執行,只需要用1秒多的時間。多進程時,每個進程各自有各自的GIL。而同一進程中的多線程受到GIL的影響,效率返而會下降。
(6) Queue是多進程安全的隊列,可以使用Queue實現多進程之間的數據傳遞?
from?multiprocessing?import?Process,Queue import?time def?write(q):for?i?in?['A','B','C','D','E']:print?('Put?%s?to?queue'?%?i)q.put(i)time.sleep(0.5)def?read(q):while?True:v?=?q.get(True)print('get?%s?from?queue'?%v)if?__name__?==?'__main__':q?=?Queue()pw?=?Process(target=write,args=(q,))pr?=?Process(target=read,args=(q,))pw.start()pr.start()pr.join()pr.terminate()輸出結果:
Put A to queue
get A from queue
Put B to queue
get B from queue
Put C to queue
get C from queue
Put D to queue
get D from queue
Put E to queue
get E from queue
(7) 進程池pool , 用于批量創建子進程,可以靈活控制子進程的數量?
from?multiprocessing?import?Pool import?time def?f(x):print?x*xtime.sleep(2)return?x*x if?__name__?==?'__main__':pool?=?Pool(processes=5)res_list?=?[]for?i?in?range(10):????????res?=?pool.apply_async(f,[i,])'''?以異步并行的方式啟動進程處理函數f,如果要同步等待的方式,可以在每次進程啟動之后調用res.get()方法,也可以使用Pool.apply'''print('-------:',i)res_list.append(res)pool.close()pool.join()for?r?in?res_list:print?'result',(r.get(timeout=5))輸出結果如下:
('-------:', 0)
('-------:', 1)
('-------:', 2)
('-------:', 3)
('-------:', 4)
('0-------:', 5)
('-------:', 6)
('-------:', 7)
1
('-------:', 8)
('-------:', 9)
4
16
9
25
36
49
64
81
result 0
result 1
result 4
result 9
result 16
result 25
result 36
result 49
result 64
result 81
如果使用同步方式,處理函數時 必須等待 前一個處理的結束,所以如果將該程序換為同步方式,輸出結果則是順序的。
(8) 多進程與多線程的對比:
from?multiprocessing?import?Process import?threading import?time lock?=?threading.Lock() def?run(info_list,n):lock.acquire()info_list.append(n)lock.release()print('%s'?%?info_list) if?__name__?==?'__main__':info?=?[]for?i?in?range(10):p?=?Process(target=run,args=[info,i])p.start()p.join()time.sleep(1)print('-----------------threading--------------')for?i?in?range(10):p?=?threading.Thread(target=run,args=[info,i])p.start()p.join()輸出結果為:
[0]
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]
-----------------threading--------------
[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6, 7]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
多進程間數據不能直接共享,每次處理函數run的結果都不能繼承。而多線程間數據可以共享,但受到GIL的影響,run函數中在將數據追加到列表時,使用lock鎖,追回完畢再釋放lock,這樣避免沖突。
轉載于:https://blog.51cto.com/caiyuanji/1966279
總結
以上是生活随笔為你收集整理的MultiProcess-MultiThread的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用Postman完成接口测试
- 下一篇: Hyperledger Fabric 1