Python 非同步多執行緒協程初探

2021-09-23 10:14:40 字數 2316 閱讀 5905

今天在知乎上看到一篇文章 為什麼有人說 python 多執行緒是雞肋? 中python中的多執行緒是單核多執行緒,是偽多執行緒!為什麼會這麼說?

由於python 中gil。正是這個鎖能保證同時只有乙個執行緒在執行。罪魁禍首::。但如果去掉gil的 python 在單執行緒條件下執行效率將近慢了2倍。~~如果一定要通過多執行緒利用多核,那只能通過c擴充套件來實現,不過這樣就失去了python簡單易用的特點。

當然,對於 io 密集型的程式,python目前對 多執行緒效能還是有很大地改善的。 python 3.4引入的 asyncio 模組來實現「協程」。

協程其實也是一種執行緒,其開銷比threading小。而且它是python3.4引入的新標準庫 asyncio。asyncio的程式設計模型是乙個訊息迴圈。需要從asyncio模組中直接獲取乙個eventloop的引用,然後把需要執行的協程扔到eventloop中執行,實現了非同步io。這裡的eventloop有點像執行緒池。

這就使得很多 io 操作有了更好的方式去解決,雖然python沒有真正意義上的多執行緒,但採用 event loop 來處理耗時的 io 操作,效果非常好。

下面簡單聊聊多執行緒協程之間的協作:

eventloop總是與thread共存,它只是負責接收事件,餘下的由thread來解決,保證併發。

下面舉乙個測試例子:

def task():

for i in range(5):

time.sleep(1)

print("task--"+str(i))

def run_loop_inside_thread(loop):

loop.run_forever()

new_loop = asyncio.new_event_loop()

asyncio.set_event_loop(new_loop)

loop = asyncio.get_event_loop()

threading.thread(target=run_loop_inside_thread, args=(loop,)).start()

loop.call_soon_threadsafe(task)

return "finish"

上面的例子,主要是在主線程中建立乙個new_loop,然後在另外的子執行緒中開啟乙個無限事件迴圈。主線程通過call_soon_threadsafe新註冊協程物件。這樣就能在子執行緒中進行事件迴圈的併發操作,同時主線程又不會被block。

如果想傳參的話,則可如下面所寫:(傳參6到more_work方法中)

.call_soon_threadsafe(more_work, 6)
其中:

event_loopasyncio的起點,是執行所有事件的起點

通過loop.run_forever()+loop.call_*實現對事件的排程

如果不加

new_loop = asyncio.new_event_loop()

asyncio.set_event_loop(new_loop)

則會報錯:runtimeerror: there is no current event loop in thread 'thread-1'。為什麼會這樣?根據asyncio的文件介紹,asyncio的事件迴圈不是執行緒安全的,乙個event loop只能在乙個執行緒內排程和執行任務,並且同一時間只有乙個任務在執行。

處於非主線程時,還需要呼叫set_event_loop方法指定乙個event loop物件,這樣get_event_loop才會獲取到被標記的event loop物件

但如果你只是執行 乙個只有主線程的demo 的話,會發現asyncio.get_event_loop()來獲取event_loop,是沒問題的。

上面的例子中的call_soon_threadsafe是asynico在多執行緒情況下專門針對執行緒安全的呼叫的解決方案。一般如果event loop在主線程中執行的話,子執行緒是不能使用它來排程任務。

值得注意點是:在非阻塞的情況下,多執行緒是同步的代表,而協程是非同步的代表。二者都可以開啟多個執行緒。在多執行緒中,多個執行緒會競爭誰先執行,乙個等待結束也不會去通知主程式,這樣沒有章法的隨機執行會造成一些資源浪費。而在協程中,多個執行緒(稱為微執行緒)的呼叫和等待都是通過明確**組織的。協程就像目標明確地執行乙個又乙個任務,而多執行緒則會在競爭過程中效能有所降低。

~~參考:

python協程與非同步協程

在前面幾個部落格中我們一一對應解決了消費者消費的速度跟不上生產者,浪費我們大量的時間去等待的問題,在這裡,針對業務邏輯比較耗時間的問題,我們還有除了多程序之外更優的解決方式,那就是協程和非同步協程。在引入這個概念之前我們先看 看這個圖 從這個我們可以看出來,假如來了9個任務,即使我們開了多程序,在業...

python 執行緒,協程

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

協程的多執行緒切換

我們知道,在乙個基於協程的應用程式中,可能會產生數以千記的協程,所有這些協程,會有乙個的排程器來統一排程。另外我們知道,高效能的程式首要注意的就是避免程式阻塞。那麼,在以協程為最小執行單位的程式中,同樣也需要確保這一點,即每乙個協程都不能發生阻塞。因為只要某乙個協程發生了阻塞,那麼整個排程器就阻塞住...