python執行緒池 協程

2021-10-16 13:05:02 字數 3190 閱讀 1180

python的執行緒雖然是真正的執行緒,但直譯器執行**時,有乙個gil鎖:global interpreter lock,任何python執行緒執行前,必須先獲得gil鎖,然後,每執行100條位元組碼,直譯器就自動釋放gil鎖,讓別的執行緒有機會執行。這個gil全域性鎖實際上把所有執行緒的執行**都給上了鎖,所以,多執行緒在python中只能交替執行,即使100個執行緒跑在100核cpu上,也只能用到1個核。

但是對於io密集型的任務,多執行緒還是起到很大效率提公升,這是協同式多工

當一項任務比如網路 i/o啟動,而在長的或不確定的時間,沒有執行任何 python **的需要,乙個執行緒便會讓出gil,從而其他執行緒可以獲取 gil 而執行 python。這種禮貌行為稱為協同式多工處理,它允許併發;多個執行緒同時等待不同事件。

乙個執行緒的執行時間可以分為3部分:執行緒的啟動時間、執行緒體的執行時間和執行緒的銷毀時間。在多執行緒處理的情景中,如果執行緒不能被重用,就意味著每次建立都需要經過啟動、銷毀和執行3個過程。這必然會增加系統相應的時間,降低了效率。

對於任務數量不斷增加的程式,每有乙個任務就生成乙個執行緒,最終會導致執行緒數量的失控,例如,整站爬蟲,假設初始只有乙個鏈結a,那麼,這個時候只啟動乙個執行緒,執行之後,得到這個鏈結對應頁面上的b,c,d,,,等等新的鏈結,作為新任務,這個時候,就要為這些新的鏈結生成新的執行緒,執行緒數量暴漲。在之後的執行中,執行緒數量還會不停的增加,完全無法控制。所以,對於任務數量不端增加的程式,固定執行緒數量的執行緒池是必要的。

python3中自帶了concurrent.futures模組,可以實現執行緒池

from concurrent.futures import threadpoolexecutor

import time

import random

from concurrent.futures import threadpoolexecutor

import time

def hello(num):

time.sleep(random.randint(1, 3))

print("{}只小鴨子,咿呀咿呀呦".format(num))

if __name__ == "__main__":

excutor1 = threadpoolexecutor(max_workers=3)

for i in range(1,8):

future = excutor1.submit(hello,i)

future.done()

with threadpoolexecutor(3) as executor1:

executor1.map(hello, [1,2,3])

在提交任務的時候,有兩種方式,一種是submit()函式,另一種是map()函式,兩者的主要區別在於:

協程:又稱微執行緒,纖程,是一種使用者態的輕量級執行緒

執行緒是系統級別的,他們是由作業系統排程。協程是程式級別的,由程式設計師根據需求自己排程。我們把乙個執行緒中的乙個個函式稱為子程式,那麼子程式在執行的過程中可以中斷去執行別的子程式。別的子程式也可以中斷回來繼續執行之前的子程式,這就是協程。也就是說同一執行緒下的一段**1執行執行著就可以中斷,然後去執行另一段**2,當再次回來執行**塊1的時候,接著從之前中斷的地方開始執行

子程式:在所有的語言中都是層級呼叫,比如a中呼叫b,b在執行過程中呼叫c,c執行完返回,b執行完返回,最後是a執行完畢。是通過棧實現的,乙個執行緒就是執行乙個子程式,子程式的呼叫總是有乙個入口,一次返回,呼叫的順序是明確的

缺點:python對協程的支援是通過generator實現的

def demo():

print('-> 開始')

x = yield #yield將接收send過來的值2賦值給x;並返回none

print('-> 接收', x) #列印 -> 接收 2

c = yield (1 + x) #接收send過來的3,並把3返回

print("x,c:",x,c) #列印 x,c: 2 3

sc = demo(1) #生成協程物件

#next將啟用協程執行到第乙個yield

print(next(sc)) #獲取到的返回值none,列印none

print(sc.send(2)) #列印3

sc.send(3) #下面沒有yield,丟擲異常stopiteration

next作用啟用協程執行到下乙個yield,等價於sc.send(none)

協程在執行過程中有四個狀態:

from inspect import  getgeneratorstate

print(getgeneratorstate(sc))

sc.send(none)

print(getgeneratorstate(sc))

sc.send(2)

print(getgeneratorstate(sc))

sc.send(3)

print(getgeneratorstate(sc))

傳統的生產者-消費者模型是乙個執行緒寫訊息,乙個執行緒取訊息,通過鎖機制控制佇列和等待,但一不小心就可能死鎖。

如果改用協程,生產者生產訊息後,直接通過yield跳轉到消費者開始執行,待消費者執行完畢後,切換回生產者繼續生產,效率極高

import threading

import time

def product(c):

print(threading.currentthread().name)

c.send(none)

for i in range(1,4):

print("蒸包子:{}".format(i))

res = c.send(i)

print("客戶反饋:{}".format(res))

time.sleep(1)

c.close()

def eat():

print(threading.currentthread().name)

res = ''

while true:

bz = yield res

if not bz:

return

print("吃包子:{}".format(bz))

res = "真好吃"

cs = eat()

product(cs)

執行緒佇列,執行緒池,協程

執行緒的queue,類似於程序 作用也是類似,queue n 規範放入值的數量 這個和之前一樣是為了實現先進先出 import queue q queue.queue 2 括號內可加入數字規範放入值的數量,不加則不會規範 q.put 123 q.put qweqwe q.put 111 print ...

執行緒佇列 執行緒池 協程

1 執行緒佇列 from multiprocessing queue joinablequeue 程序ipc佇列 from queue import queue 執行緒佇列 先進先出 from queue import lifoqueue 後進先出的 方法都是一樣的 put get put nowa...

python 執行緒,協程

本文 threading用於提供執行緒相關的操作。執行緒是應用程式中工作的最小單元,它被包含在程序之中,是程序中的實際運作單位。一條執行緒指的是程序中乙個單一順序的控制流,乙個程序中可以併發多個執行緒,每條執行緒並行執行不同的任務。threading 模組建立在 thread 模組之上。thread...