日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

MultiProcess-MultiThread

發(fā)布時(shí)間:2025/6/15 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MultiProcess-MultiThread 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

聽到一些關(guān)于python多進(jìn)程與多線的例子,感覺比較經(jīng)典,把一些例子分享一下.

內(nèi)容如下:

? ? Process、Thread、GIL、Process fork、Multiprocessing、Queue、ProcessPool、Multiprocess-Multithread comparison


(1) Process : 程序的一次執(zhí)行(程序編寫完畢后代碼裝載入內(nèi)存,系統(tǒng)分配資源運(yùn)行)。每個(gè)進(jìn)程有自己的內(nèi)存空間、數(shù)據(jù)棧等,只能使用進(jìn) 程間通訊,而不能直接共享信息?


(2) Thread線程:所有線程運(yùn)行在同一個(gè)進(jìn)程中,共享相同的運(yùn)行環(huán)境。 每個(gè)獨(dú)立的線程有一個(gè)程序運(yùn)行的入口、順序執(zhí)行序列和程序的出口; 線程的運(yùn)行可以被搶占(中斷),或暫時(shí)被掛起 (睡眠),讓其他線程運(yùn)行(讓步);一個(gè)進(jìn)程中的各個(gè)線程間共享同一片數(shù)據(jù)空間?


(3) 全局解釋器鎖GIL?

? ? GIL全稱全局解釋器鎖Global Interpreter Lock,GIL并不是Python的特性,它是在實(shí)現(xiàn)Python解析器(CPython)時(shí) 所引入的一個(gè)概念。?

? ? GIL是一把全局排他鎖,同一時(shí)刻只有一個(gè)線程在運(yùn)行。 毫無疑問全局鎖的存在會對多線程的效率有不小影響。甚至就幾乎等于Python是個(gè)單線程的程序。?

? ? multiprocessing庫的出現(xiàn)很大程度上是為了彌補(bǔ)thread庫因?yàn)?/span> GIL而低效的缺陷。它完整的復(fù)制了一套thread所提供的接口方便遷移。唯一的不同就是它使用了多進(jìn)程而不是多線程。每個(gè)進(jìn)程有自己的獨(dú)立的GIL,因此也不會出現(xiàn)進(jìn)程之間的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()#以單線程、阻塞的方式順序運(yùn)行兩次my_counter函數(shù)end_time?=?time.time()print("Total?time:{}").format(end_time?-?start_time)if?__name__=="__main__":main()

執(zhí)行結(jié)果如下:

Total time:12.7875118256


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()thread_array[tid]?=?tfor?i?in?range(2):thread_array[i].join()#以多進(jìn)程、并發(fā)的方式運(yùn)行兩次my_counter函數(shù)end_time?=?time.time()print("Total?time:{}").format(end_time?-?start_time)if?__name__=="__main__":main()

執(zhí)行結(jié)果如下:

Total time:15.8216409683


上述兩個(gè)例子的結(jié)果發(fā)現(xiàn):單線程運(yùn)行兩次函數(shù)的時(shí)間 ? 要比 ? 兩個(gè)線程同時(shí)運(yùn)行函數(shù)的時(shí)間短(僅限于本例)。


(4) fork操作:?

調(diào)用一次,返回兩次。因?yàn)椴僮飨到y(tǒng)自動把當(dāng)前進(jìn)程(稱為父 進(jìn)程)復(fù)制了一份(稱為子進(jìn)程),然后分別在父進(jìn)程和子進(jìn) 程內(nèi)返回。子進(jìn)程永遠(yuǎn)返回0,而父進(jìn)程返回子進(jìn)程的ID。子 進(jìn)程只需要調(diào)用getppid()就可以拿到父進(jìn)程的ID

例:

import?os print?'Process?(%s)?start?...'?%?os.getpid() pid=os.fork() if?pid==0:print?'I?am?child?process?(%s)?and?my?parent?is?(%s)'?%?(os.getpid(),os.getppid()) else:print?'I?(%s)?just?created?a?child?process?(%s).'?%?(os.getpid(),pid)

執(zhí)行結(jié)果如下:

Process (16480) start ...

I (16480) just created a child process (16481).

I am child process (16481) and my parent is (16480)


(5) multiprocessing是跨平臺版本的多進(jìn)程模塊,它提供了一個(gè)Process類來代表一個(gè)進(jìn)程對象,下面是示例代碼:?

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()#使用多進(jìn)程并發(fā)的方式執(zhí)行函數(shù)f

這個(gè)程序如果用單進(jìn)程寫則需要執(zhí)行10秒以上的時(shí)間, 而用多進(jìn)程則啟動10個(gè)進(jìn)程并行執(zhí)行,只需要用1秒多的時(shí)間。多進(jìn)程時(shí),每個(gè)進(jìn)程各自有各自的GIL。而同一進(jìn)程中的多線程受到GIL的影響,效率返而會下降。


(6) Queue是多進(jìn)程安全的隊(duì)列,可以使用Queue實(shí)現(xiàn)多進(jìn)程之間的數(shù)據(jù)傳遞?

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()

輸出結(jié)果:

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) 進(jìn)程池pool , 用于批量創(chuàng)建子進(jìn)程,可以靈活控制子進(jìn)程的數(shù)量?

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,])'''?以異步并行的方式啟動進(jìn)程處理函數(shù)f,如果要同步等待的方式,可以在每次進(jìn)程啟動之后調(diào)用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))

輸出結(jié)果如下:

('-------:', 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

如果使用同步方式,處理函數(shù)時(shí) 必須等待 前一個(gè)處理的結(jié)束,所以如果將該程序換為同步方式,輸出結(jié)果則是順序的。


(8) 多進(jìn)程與多線程的對比

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()

輸出結(jié)果為:

[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]


多進(jìn)程間數(shù)據(jù)不能直接共享,每次處理函數(shù)run的結(jié)果都不能繼承。而多線程間數(shù)據(jù)可以共享,但受到GIL的影響,run函數(shù)中在將數(shù)據(jù)追加到列表時(shí),使用lock鎖,追回完畢再釋放lock,這樣避免沖突。

轉(zhuǎn)載于:https://blog.51cto.com/caiyuanji/1966279

總結(jié)

以上是生活随笔為你收集整理的MultiProcess-MultiThread的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。