9 協程 協程理論

2022-02-27 16:10:14 字數 3044 閱讀 2384

本節的主題是基於單執行緒來實現併發,即只用乙個主線程(很明顯可利用的cpu只有乙個)情況下實現併發,

為此我們需要先回顧下併發的本質:切換+儲存狀態

ps:在介紹程序理論時,提及程序的三種執行狀態,而執行緒才是執行單位,所以也可以將上圖理解為執行緒的三種狀態
cpu正在執行乙個任務,會在兩種情況下切走去執行其他的任務(切換由作業系統強制控制),該任務發生了阻塞另外一種情況是該任務計算的時間過長或有乙個優先順序更高的程式替代了它

其中第二種情況並不能提公升效率,只是為了讓cpu能夠雨露均沾,實現看起來所有任務都被「同時」執行的效果,如果多個任務都是純計算的,這種切換反而會降低效率。

為此我們可以基於yield來驗證。yield本身就是一種在單執行緒下可以儲存任務執行狀態的方法,我們來簡單複習一下:

1 yiled可以儲存狀態,yield的狀態儲存與作業系統的儲存執行緒狀態很像,但是yield是**級別控制的,更輕量級

2 send可以把乙個函式的結果傳給另外乙個函式,以此實現單執行緒內程式之間的切換

(1)序列執行

#

序列執行

import

time

defconsumer(res):

'''任務1:接收資料,處理資料

'''pass

defproducer():

'''任務2:生產資料

'''res=

for i in range(10000000):

return

resstart=time.time()

res=producer()

consumer(res)

#6.782020092010498

#寫成consumer(producer())會降低執行效率

#7.082412242889404

consumer(producer())

print(time.time()-start)

(2)基於yield併發執行

第一種情況的切換。在任務一遇到io情況下,切到任務二去執行,這樣就可以利用任務一阻塞的時間完成任務二的計算,效率的提公升就在於此。

(1)yield並不能實現遇到io切換

import

time

defconsumer():

'''任務1:接收資料,處理資料

'''while

true:

x=yield

defproducer():

'''任務2:生產資料

'''g=consumer()

next(g)

for i in range(10000000):

g.send(i)

time.sleep(2)

start=time.time()

producer()

#併發執行,但是任務producer遇到io就會阻塞住,並不會切到該執行緒內的其他任務去執行

協程的本質就是在單執行緒下,由使用者自己控制乙個任務遇到io阻塞了就切換另外乙個任務去執行,以此來提公升效率。

為了實現它,我們需要找尋一種可以同時滿足以下條件的解決方案:

1. 可以控制多個任務之間的切換,切換之前將任務的狀態儲存下來,以便重新執行時,可以基於暫停的位置繼續執行。

2. 作為1的補充:可以檢測io操作,在遇到io操作的情況下才發生切換

協程:是單執行緒下的併發,又稱微執行緒,纖程。英文名coroutine。一句話說明什麼是執行緒:協程是一種使用者態的輕量級執行緒,即協程是由使用者程式自己控制排程的。、

需要強調的是:

1. python的執行緒屬於核心級別的,即由作業系統控制排程(如單執行緒遇到io或執行時間過長就會被迫交出cpu執行許可權,切換其他執行緒執行)

2. 單執行緒內開啟協程,一旦遇到io,就會從應用程式級別(而非作業系統)控制切換,以此來提公升效率(!!!非io操作的切換與效率無關)

對比作業系統控制線程的切換,使用者在單執行緒內控制協程的切換

#

優點如下:

1. 協程的切換開銷更小,屬於程式級別的切換,作業系統完全感知不到,因而更加輕量級

2. 單執行緒內就可以實現併發的效果,最大限度地利用cpu

#

缺點如下:

1. 協程的本質是單執行緒下,無法利用多核,可以是乙個程式開啟多個程序,每個程序內開啟多個執行緒,每個執行緒內開啟協程

2. 協程指的是單個執行緒,因而一旦協程出現阻塞,將會阻塞整個執行緒

#

總結協程特點:

1、必須在只有乙個單執行緒裡實現併發

2、修改共享資料不需加鎖

3、使用者程式裡自己儲存多個控制流的上下文棧

4、附加:乙個協程遇到io操作自動切換到其它協程(如何實現檢測io,yield、greenlet都無法實現,就用到了gevent模組(select機制))

協程巢狀協程

import asyncio import functools 第三層協程 async def test1 print 我是test1 await asyncio.sleep 1 print test1已經睡了1秒 await asyncio.sleep 3 print test1又睡了3秒 ret...

python協程與非同步協程

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

python協程使用 協程的案例

概念 使用者層面在乙個執行緒中進行多工切換的機制,比執行緒更加輕量級 實現併發量更大 協程的使用 使用第三方庫 gevent gevent 是乙個基於協程的 python 網路庫,在遇到 io 阻塞時,程式會自動進行切換,可以讓我們用同步的放肆寫非同步 io 協程的使用 from gevent im...