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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

python多线程多进程多协程_python 多进程、多线程、协程

發(fā)布時間:2025/3/20 python 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python多线程多进程多协程_python 多进程、多线程、协程 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1、python的多線程

多線程就是在同一時刻執(zhí)行多個不同的程序,然而python中的多線程并不能真正的實現(xiàn)并行,這是由于cpython解釋器中的GIL(全局解釋器鎖)搗的鬼,這把鎖保證了同一時刻只有一個線程被執(zhí)行。

多線程的特點:

線程比進程更輕量級,創(chuàng)建一個線程要比創(chuàng)建一個進程快10-100倍。

線程共享全局變量。

由于GIL的原因,當(dāng)一個線程遇到IO操作時,會切換到另一個線程,所以線程適合IO密集型操作。

在多核cpu系統(tǒng)中,最大限度的利用多核,可以開啟多個線程,開銷比進程小的多,但是這并不適合python。

多線程互斥鎖:

因為線程共享全局變量,所以需要互斥鎖去限制線程對全局變量的更改。

假設(shè),當(dāng)一個線程在執(zhí)行到獲取全局變量的時候,這個后GIL切換到另一個線程執(zhí)行,這個時候新的線程為全局變量+1后切換回之前的線程,之前的線程中的全局變量還是+1前的值,所以需要互斥鎖。

為什么有了GIL鎖還要互斥鎖呢?

GIL鎖只是控制同一時刻下只有一個線程被執(zhí)行,這并不能控制同一時刻只有一個線程去獲取并更改全局變量,所以需要使用互斥鎖。

多線程的實現(xiàn):

#導(dǎo)入threading模塊

importthreading#定義全局變量

i=0#定義互斥鎖

mutex =threading.Lock()defa():#申明全局變量i

globalifor j in range(2000000):#獲取互斥鎖

mutex.acquire()

i+=1

#釋放互斥鎖

mutex.release()defb():globalifor j in range(2000000):

mutex.acquire()

i+=1mutex.release()#創(chuàng)建線程

t1 = threading.Thread(target=a)

t2= threading.Thread(target=b)#開啟線程

t1.start()

t2.start()#等待所有線程結(jié)束

t1.join()

t2.join()print(i)

2、python中的多進程

python的多線程不能利用多核的優(yōu)勢,如果想要充分的利用多核cpu的資源,python中大部分情況需要使用多進程。

python多進程的特點:

進程間不共享全局變量,進程修改的數(shù)據(jù)僅限于該進程內(nèi)。

進程創(chuàng)建和銷毀的開銷比較大。

相對于線程,進程更適合與計算密集型操作。

能充分利用多核的優(yōu)勢。

進程間通信:

既然進程間中不公共享全局變量,那么多進程間怎么進行通信呢?可以使用multiprocessing中的Queue模塊,當(dāng)然也可以使用socket、管道、共享內(nèi)存等方式。

多進程的實現(xiàn):

#導(dǎo)入multiprocessin模塊

importmultiprocessing#創(chuàng)建隊列

queue =multiprocessing.Queue()#定義全局變量

a =0#定義函數(shù)

defwork1(num):#獲取隊列中的數(shù)據(jù),如果沒有數(shù)據(jù),將堵塞

a =queue.get()#將隊列中的數(shù)據(jù)+2000000次num

for i in range(2000000):

a+=num#將數(shù)據(jù)存放在隊列中

queue.put(a)#打印最終結(jié)果

print("work1",a)#定義函數(shù)

defwork2():#申明全局變量a

globala#將a+2000000次1

for i in range(2000000):

a+=1

#打印最總結(jié)果

print("work2",a)#將a存放在隊列中

queue.put(a)#創(chuàng)建進程

p1 = multiprocessing.Process(target=work1, args=(2,))

p2= multiprocessing.Process(target=work2)#啟動進程

p1.start()

p2.start()#等待進程結(jié)束

p1.join()

p2.join()#獲取隊列中的數(shù)據(jù)

a =queue.get()#打印a

print(a)

進程池的實現(xiàn)

進程池能減少重復(fù)創(chuàng)建和銷毀進程的開銷問題

#導(dǎo)入需要的模塊

importmultiprocessingimporttimeimportrandom#定義函數(shù)

defwork(num):print("num=",num)

time.sleep(random.randint(0,2))#創(chuàng)建進程池,設(shè)置進程的數(shù)量

pool = multiprocessing.Pool(3)for i in range(10):#開啟進程

pool.apply_async(work, args=(i,))#設(shè)置等待時間,等待所有進程結(jié)束

time.sleep(20)

3、python中的協(xié)程

在linux中線程就是輕量級的進程,而我們通常也把協(xié)程稱為輕量級的線程。

對比進程和協(xié)程:

進程是內(nèi)核調(diào)度,而協(xié)程是在用戶態(tài)調(diào)度,所以說進程的上下文在內(nèi)核態(tài)保存恢復(fù),而協(xié)程是在用戶態(tài)保存恢復(fù)的,所以協(xié)程的開銷比進程低。

進程會被搶占,而協(xié)程不會,也就是說協(xié)程如果不主動讓出cpu,那么其他的協(xié)程就沒有執(zhí)行的機會。

進程所需要的內(nèi)存比協(xié)程大得多

對比線程和協(xié)程:

線程的上下文切換成本相對于協(xié)程來說比較高。

線程的切換由操作系統(tǒng)來控制,而協(xié)程的切換由我們自己控制。

yield實現(xiàn)協(xié)程:

#定義兩個函數(shù)

defwork1():whileTrue:print("work1")#當(dāng)程序運行到y(tǒng)ield就會暫停,等待下次的next調(diào)用,然后繼續(xù)執(zhí)行

yield

defwork2():whileTrue:print("work2")yieldw1=work1()

w2=work2()whileTrue:#使用next函數(shù)啟動

next(w1)

next(w2)

greenlet實現(xiàn)協(xié)程:

greenlet安裝:

sudo pip3 install greenlet

code:

#導(dǎo)入greenlet模塊

from greenlet importgreenletdefwork1():for i in range(10):print("work1")#打印過后跳轉(zhuǎn)至協(xié)程g2繼續(xù)執(zhí)行

g2.switch()defwork2():for i in range(10):print("work2")#打印后跳轉(zhuǎn)至協(xié)程g1繼續(xù)執(zhí)行

g1.switch()#創(chuàng)建協(xié)程g1

g1 =greenlet(work1)#創(chuàng)建協(xié)程g2

g2 =greenlet(work2)#跳轉(zhuǎn)至協(xié)程g1

g1.switch()

gevent實現(xiàn)協(xié)程:

gevent是基于greenlet的并發(fā)網(wǎng)絡(luò)庫,每當(dāng)有一個協(xié)程堵塞的時,程序?qū)⒆詣诱{(diào)度。

monkey-patching:

一般稱為猴子補丁,這個補丁能直接修改標(biāo)準庫里面大部分的阻塞式系統(tǒng)調(diào)用。但是如果在復(fù)雜的生產(chǎn)環(huán)境中使用了這些標(biāo)準庫,可能就會因為打了補丁而出現(xiàn)奇怪的問題。

gevent安裝:

sudo pip3 install gevent

code:

#導(dǎo)入所需要的模塊

importgeventimporttimefrom gevent importmonkey#猴子補丁,monkey.patch_all()方法將所有的標(biāo)準庫都替換掉#使用猴子補丁褒貶不一,但是官網(wǎng)上還是建議使用patch_all(),而且在程序的第一行就執(zhí)行

monkey.patch_all()deff(n):for i inrange(n):print(i)#設(shè)置延時

time.sleep(0.5)#如果沒有導(dǎo)入monkey模塊的話,需要使用gevent.sleep()

#gevent.sleep(0.5)

#----------------寫法一--------------------#創(chuàng)建greenlet協(xié)程對象#g1 = gevent.spawn(f,5)#g2 = gevent.spawn(f,5)#g3 = gevent.spawn(f,5)#等待所有g(shù)reenlet攜程結(jié)束后退出#g1.join()#g2.join()#g3.join()

#----------------寫法二--------------------

gevent.joinall([gevent.spawn(f,5), gevent.spawn(f,5), gevent.spawn(f,5)])

總結(jié)

以上是生活随笔為你收集整理的python多线程多进程多协程_python 多进程、多线程、协程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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