Python3學習筆記 清晰理解協程

2021-09-14 05:18:25 字數 3785 閱讀 2331

在了解協程之前,我們先簡單了解一下程序與執行緒,併發與並行的概念。

什麼是協程?我們先來看下對協程的概括:協程被稱為微執行緒或者纖程,是一種使用者態的輕量級執行緒。

其本質就是乙個單執行緒,協程的作用就是在乙個執行緒中人為控制**塊的執行順序。(記住這句就可以了)

具體解釋如下:

在乙個執行緒中有很多函式,我們稱這些函式為子程式。當乙個子程式a在執行過程中可以中斷執行,切換到子程式b,執行子程式b。而在適當的時候子程式b還可以切換回子程式a,去接著子程式a之前中斷的地方(即回到子程式a切換到子程式b之前的狀態)繼續往下執行,這個過程,我們可以稱之為協程。看到這段解釋,是不是覺得和yield關鍵字的操作很相似。

**tip:**關於yield和生成器不了解的,可以看[《python3學習筆記:清晰理解迭代器、生成器以及yield表示式》][python3學習筆記:清晰理解迭代器、生成器以及yield表示式],下面會涉及到。

為了方便理解,我們用乙個簡單示例來展示協程的工作大致工作方式,以下是乙個經典的生產者-消費者模型:

import time

defconsumer()

:print

("[消費者]:我準備好接收來自生產者的訊息了!"

)while

true

: y =

(yield

) time.sleep(1)

print

("[消費者]:接收到來自生產者的訊息 %s"

% y)

defproducer()

: c = consumer(

) c.send(

none

) i =

1while i <5:

time.sleep(1)

print

("[生產者]:向消費者傳送訊息 %s"

% i)

c.send(i)

i +=

1 c.close(

)producer(

)

列印結果:

[消費者]:我準備好接收來自生產者的訊息了!

[生產者]:向消費者傳送訊息 1

[消費者]:接收到來自生產者的訊息 1

[生產者]:向消費者傳送訊息 2

[消費者]:接收到來自生產者的訊息 2

[生產者]:向消費者傳送訊息 3

[消費者]:接收到來自生產者的訊息 3

[生產者]:向消費者傳送訊息 4

[消費者]:接收到來自生產者的訊息 4

示例中,消費者是個生成器,生產者與消費者的互動如下:

生產者先在內部通過c.send(none)啟用了消費者,生產者中斷執行,消費者獲取程式控制權開始執行

消費者執行中遇到yield後被掛起,停止了執行,等待生產者傳送訊息,並將程式控制權返回給生產者,生產者接著上次中斷的地方繼續執行

生產者進入while迴圈,每隔1秒,向消費者傳送一條訊息,消費者的yield收到訊息後,從上次yield中斷的地方繼續往後執行,當再次遇到yield後重複中的流程

可以看到,消費者每次都需要等待生產者傳入訊息之後才會繼續執行之後的任務。

以上是協程的乙個大概的工作方式,可以人為控制子程式(即函式)的執行順序,人為的切換子程式的執行。上述示例比較簡單,也並不是真正的協程,這是協程的工作方式而已。下面我們來看一下真正的協程是什麼樣的。

我們下面要實現的真正的協程,需要使用python標準庫中的asyncio模組。asyncio是在python3.4時引入的,在python3.5的時候,asyncio新增了兩個關鍵字aysncawaitasync關鍵字可以將乙個函式修飾為協程物件,await關鍵字可以將需要耗時的操作掛起,一般多是io操作。(注:如果使用的是python3.4請用@asyncio.coroutine代替asyncyield from代替await

import asyncio

import time

start = time.time(

)async

defteach_student

(n, t)

:print

("開始輔導學生 %d 。。。"

% n)

await asyncio.sleep(t)

print

("學生 %d 結束輔導"

% n)

t1 = teach_student(1,

2)t2 = teach_student(2,

1)t3 = teach_student(3,

3)loop = asyncio.get_event_loop(

)loop.run_until_complete(asyncio.gather(t1, t2, t3)

)loop.close(

)end = time.time(

)print

(, end-start)

列印結果:

開始輔導學生 1  。。。

開始輔導學生 2 。。。

開始輔導學生 3 。。。

學生 2 結束輔導

學生 1 結束輔導

學生 3 結束輔導

上面是模擬一段1位老師3位輔導學生功課的場景,就是我們在一開始提到的併發中的例子。下面我們來解析一下上面的示例:

以上就是乙個真正的協程示例,如果老師輔導學生,每次都等輔導的學生完成功課後,在輔導下乙個學生,會花費足足7秒時間(同步順序執行)。而協程的方式,則是老師在輔導完一位學生後,就讓學生自己做功課,老師不等待,立馬開始輔導下一位學生,極大的縮短了時間,提高了效率(非同步執行)。並且從以上示例也可以看出使用asyncio實現的協程的一些特性:

在了解為什麼要使用協程之前,我們要先了解多執行緒在單核cpu下的執**況。當你的電腦只是單核cpu時,所謂的多執行緒的執行,其實只是cpu在不停的切換執行的執行緒,例如執行緒a執行0.0.1秒後,切換到執行緒b執行0.01秒,再切換到執行緒c執行0.01秒,但是同一時間,只有乙個執行緒在執行。只有在多核cpu時,多執行緒才有可能做到幾個執行緒同時執行。

但是,我們在python中這一情況又有所不同。我們廣泛使用的python直譯器是cpython(我們經常說的python2和python3 就是直譯器cpython的python版本) ,除此之外還有jpython、pypy等其他直譯器。但是cpython才是使用最廣泛的。而cpython直譯器中存在gil鎖(全域性直譯器鎖 global interpreter lock,注意gil不是python語言的特性,只存在cpython直譯器中),它的作用就是防止多執行緒時執行緒搶占資源,所以在同一時間只允許乙個執行緒在執行,即使在多核cpu情況下也是一樣 ,所以cpu的單核和多核對於多執行緒的執行效率並沒有多大幫助,還是執行緒之間的不停切換。

基於以上情況,在一些多執行緒的場景時,我們就可以使用協程來代替多執行緒,並且可以做的更靈活。我們下面來看下協程的優勢:

所以,在處理一些高併發場景時,有時協程比多執行緒更加適合,比如做爬蟲時。

Python3學習筆記

最近在起步學python,聚合一下這個過程中蒐集的資源和對一些基本知識做個小總結,語法基於python3,方便以後查詢。python官方文件 不錯的基礎課程 基本語法 演算法 建模 練習 以下是整理常用可能遺忘的基礎點 python3中的輸入是input 獲得使用者輸入的字串 a input ple...

python3學習筆記

redis訊息佇列的使用 coding utf 8 created on tue mar 26 15 58 34 2019 author admin import redis class redisqueue object def init self,name,namespace queue red...

python3 學習筆記

python3學習筆記 python基礎 輸出 print 括號中加上想要輸出的資料,就可以將指定內容輸出至螢幕。1.輸出的時候要注意資料型別。字串,整數等等 2.括號中可以包含多個字串,使用逗號隔開就可以了。但是每次輸出遇到這個連線逗號的時候都會輸出乙個空格。3.括號中的內容也可以是變數名和計算公...