執行緒丶程序丶協程(三)協程

2021-08-21 18:27:31 字數 3215 閱讀 9261

協程,又稱微執行緒,纖程。英文名coroutine。

協程是python個中另外一種實現多工的方式,只不過比執行緒更小占用更小執行單元(理解為需要的資源)。 為啥說它是乙個執行單元,因為它自帶cpu上下文。這樣只要在合適的時機, 我們可以把乙個協程 切換到另乙個協程。 只要這個過程中儲存或恢復 cpu上下文那麼程式還是可以執行的。

通俗的理解:在乙個執行緒中的某個函式,可以在任何地方儲存當前函式的一些臨時變數等資訊,然後切換到另外乙個函式中執行,注意不是通過呼叫函式的方式做到的,並且切換的次數以及什麼時候再切換到原來的函式都由開發者自己確定

在實現多工時, 執行緒切換從系統層面遠不止儲存和恢復 cpu上下文這麼簡單。 作業系統為了程式執行的高效性每個執行緒都有自己快取cache等等資料,作業系統還會幫你做這些資料的恢復操作。 所以執行緒的切換非常耗效能。但是協程的切換只是單純的操作cpu的上下文,所以一秒鐘切換個上百萬次系統都抗的住。

greenlet是python的乙個c擴充套件,**於stackless python,旨在提供可自行排程的『微執行緒』, 即協程。generator實現的協程在yield value時只能將value返回給呼叫者(caller)。 而在greenlet中,target.switch(value)可以切換到指定的協程(target), 然後yield value。greenlet用switch來表示協程的切換,從乙個協程切換到另乙個協程需要顯式指定。

為了更好使用協程來完成多工,python中的greenlet模組對其封裝,從而使得切換任務變的更加簡單

使用如下命令安裝greenlet模組(在ubuntu的命令列下):

sudo pip3 install greenlet
也在pycharm中配置可用資源:

#切換到gr1中執行

gr1.switch()

從圖中**可以看出,兩個test協程之間必須通過switch方法來進行切換才能實現非同步。

下面介紹乙個更棒的模組:

python有乙個比greenlet更強大的並且能夠自動切換任務的模組gevent

其原理是當乙個greenlet遇到io(指的是input output 輸入輸出,比如網路、檔案操作等)操作時,比如訪問網路,就自動切換到其他的greenlet,等到io操作完成,再在適當的時候切換回來繼續執行。

由於io操作非常耗時,經常使程式處於等待狀態,有了gevent為我們自動切換協程,就保證總有greenlet在執行,而不是等待io。

import time

import gevent

def work1():

for i in range(5):

print("work1 -----1")

time.sleep(0.5)

def work2():

for i in range(5):

print("work2 -----2")

time.sleep(0.5)

# 建立攜程並指派任務

g1 = gevent.spawn(work1)

g2 = gevent.spawn(work2)

# 等待協程執行完成再關閉主線程

g1.join()

g2.join()

執行結果

work1 -----1

work1 -----1

work1 -----1

work1 -----1

work1 -----1

work2 -----2

work2 -----2

work2 -----2

work2 -----2

work2 -----2

我們是希望 gevent 幫我們我們自動切換協程以達到work1 和 work2 交替執行的目的,但並沒有達到我們的效果

原因是因為 time.sleep(0.2) 並沒有被正確的識別到,所以要使用下面的 gvent.sleep() 來實現延時(耗時)操作

# 使用gevent.sleep() 使得延時操作能夠被gevent識別

gevent.sleep(0.5)

問題是,如果我們以前的**中大量使用了time.sleep()等耗時方法,如果全部改為gevent.sleep()為了讓程式更好的相容time.sleep()我們可以給程式打補丁,以實現相容

關於猴子補丁為啥叫猴子補丁,據說是這樣子的:

這個叫法起源於zope框架,大家在修正zope的bug的時候經常在程式後面追加更新部分,這些被稱作是「雜牌軍補丁(guerilla patch)」,後來guerilla就漸漸的寫成了gorllia((猩猩),再後來就寫了monkey(猴子),所以猴子補丁的叫法是這麼莫名其妙的得來的。

猴子補丁主要有以下幾個用處:

# 打補丁,讓gevent識別自己提供或者網路請求的耗時操作

from gevent import monkey

monkey.patch_all()

在執行時替換方法、屬性等

在不修改第三方**的情況下增加原來不支援的功能

在執行時為記憶體中的物件增加patch而不是在磁碟的源**中增加

程序、執行緒、協程的關係

執行緒丶程序丶協程(二)程序 2

當需要建立的子程序數量不多時,可以直接利用multiprocessing中的process動態成生多個程序,但如果是上百甚至上千個目標,手動的去建立程序的工作量巨大,此時就可以用到multiprocessing模組提供的pool方法。初始化pool時,可以指定乙個最大程序數,當有新的請求提交到poo...

程序 執行緒 協程

多程序多執行緒的最終目地都是為了加快任務處理的時間,但是受限於cpu核數 只有多核才能實現並行,任務耗時 單核任務耗時 cpu核數 那麼在單核上執行多程序多執行緒是不是沒有用了,加快不了處理的速度了?答案肯定是不是的,不然這個東西設計出來太雞肋了,那它們加快處理的原理是什麼呢?乙個程序耗時 b程序耗...

程序 執行緒 協程

程序是系統資源分配的最小單位,系統由乙個個程序 程式 組成。一般情況下,包括文字區域 text region 資料區域 data region 和堆疊 stack region 檔案描述符表 程序每次開啟乙個檔案,系統就會在該程序的使用者檔案描述符表中分配乙個相應的表項,表項的索引返回給該程序,用於...