1.定義:
纖程,微執行緒。是允許在不同入口點不同位置暫停或開始的電腦程式,簡單來說,協程就是可以暫停執行的函式。
2. 協程原理 :
記錄乙個函式的上下文,協程排程切換時會將記錄的上下文儲存,在切換回來時進行調取,恢復原有的執行內容,以便從上一次執行位置繼續執行。
協程本質上就是乙個執行緒,以前多執行緒任務的切換是由作業系統控制的,遇到i/o阻塞就自動切換,現在我們用協程的目的就是較少作業系統切換的開銷(開關執行緒,建立暫存器、堆疊等,在他們之間進行切換等),在我們自己的程式(應用層面)裡面來控制任務的切換。對於單執行緒下,我們不可避免程式**現io操作,但如果我們能在自己的程式中(即使用者程式級別,而非作業系統級別)控制單執行緒下的多個任務能在乙個任務遇到io阻塞時就切換到另外乙個任務去計算,這樣就保證了該執行緒能夠最大限度地處於就緒態,即隨時都可以被cpu執行的狀態,相當於我們在使用者程式級別將自己的io操作最大限度地隱藏起來,從而可以迷惑作業系統,讓其看到:該執行緒好像是一直在計算,io比較少,從而更多的將cpu的執行許可權分配給我們的執行緒。
3.
協程優缺點
優點
協程完成多工占用計算資源很少
由於協程的多工切換在應用層完成,因此切換開銷少,最大限度地利用cpu
協程為單執行緒程式,無需進行共享資源同步互斥處理
缺點 協程的本質是乙個單執行緒,無法利用計算機多核資源
python3.5
以後,使用標準庫
asyncio
和async/await
語法來編寫併發**。
asyncio
庫通過對非同步
io行為的支援完成python
的協程。雖然官方說asyncio
是未來的開發方向,但是由於其生態不夠豐富,大量的客戶端不支援awaitable
需要自己去封裝,所以在使用上存在缺陷。更多時候只能使用已有的非同步庫(asyncio
等),功能有限。
示例:
import asyncio
async def fun1():
print("start1")
# 遇到阻塞跳出
await asyncio.sleep(3)
print("end1")
async def fun2():
print("start2")
# 遇到阻塞跳出
await asyncio.sleep(2)
print("end2")
cor1 = fun1()
cor2 = fun2()
tasks = [asyncio.ensure_future(cor1),
asyncio.ensure_future(cor2)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
# start1
# start2
# end2
# end1
安裝 :sudo pip3 install greenlet
函式:
g = greenlet.greenlet(func)功能:建立協程物件
引數:協程函式
返回值:greenlet 協程函式物件
g.switch()功能:選擇要執行的協程函式
示例:
"""
協程行為展示
"""from greenlet import greenlet
def fun1():
print("執行fun1")
# 跳轉執行fun2
gr2.switch()
print("結束fun1")
# 跳回fun2繼續往下執行,而不是從fun2第一行開始
gr2.switch()
def fun2():
print("執行fun2")
# 跳回fun1繼續往下執行,而不是從fun1第一行開始
gr1.switch()
print("結束fun2")
# 將函式變為協成函式
gr1 = greenlet(fun1)
gr2 = greenlet(fun2)
gr1.switch()
安裝:sudo pip3 install gevent
函式:
gevent.spawn(func,ar**)功能: 生成協程物件
引數:func
協程函式
ar**
給協程函式傳參(不定參)
返回值: 協程物件
gevent.joinall(list
,[timeout])
功能: 阻塞等待協程執行完畢
引數:list
協程物件列表
timeout
超時時間
gevent.sleep(sec)* gevent協程只有在遇到gevent指定的阻塞行為時才會自動在協程之間進行跳轉,如gevent.joinall(),gevent.sleep()帶來的阻塞功能: gevent
睡眠阻塞
引數:睡眠時間
monkey指令碼
作用:
在gevent
協程中,協程只有遇到
gevent
指定型別的阻塞才能跳轉到其他協程,因此,我們希望將普通的io
阻塞行為轉換為可以觸發
gevent
協程跳轉的阻塞,以提高執行效率。
轉換方法:
gevent
提供了乙個指令碼程式
monkey,
可以修改底層解釋
io阻塞的行為,將很多普通阻塞轉換為gevent
阻塞。
使用方法:
【示例:1】 匯入
monkey
from gevent import monkey
【2】 執行相應的指令碼,例如轉換
socket
中所有阻塞
monkey.patch_socket()
【3】 如果將所有可轉換的
io阻塞全部轉換則執行
all
monkey.patch_all()
【4】 注意:指令碼執行函式需要在對應模組匯入前執行
"""
基於協程的tcp併發
"""import gevent
from gevent import monkey
monkey.patch_socket() # 執行指令碼修改socket阻塞行為
from socket import *
def handle(c):
while true:
data = c.recv(1024).decode() # 屬於協程阻塞,不影響其他客戶端
if not data:
return
print(data)
c.send(b'ok')
# 建立套接字
s = socket()
s.setsockopt(sol_socket, so_reuseaddr, 1)
s.bind(('127.0.0.1', 8888))
s.listen(5)
# 迴圈接收來自客戶端請求
while true:
c, addr = s.accept()
print("connect from", addr)
# handle(c) # 迴圈方案
gevent.spawn(handle, c) # 協程方案
python之協程建立
協程,是充分利用cpu給該執行緒的時間,在乙個執行緒裡放置多個任務,當某個任務阻塞時就執行下乙個任務。其特點是能夠記住這些任務執行到哪一步了,下次再執行該任務的時候回從上次阻塞的地方繼續開始。建立協程需要使用gevent模組。如下 import gevent gevent協程中,遇到需要耗費時間的操...
Python 高階 之 協程
協程的概念級描述 與執行緒對比 知乎 鏈結 執行緒有兩個必須要處理的問題 一是碰著阻塞式i o會導致整個程序被掛起 二是由於缺乏時鐘阻塞,程序需要自己擁有排程執行緒的能力。如果一種實現使得每個執行緒需要自己通過呼叫某個方法,主動交出控制權。那麼我們就稱這種執行緒是協作式的,即是協程。在python中...
Python學習之協程
我們都知道執行緒間的任務切換是由作業系統來控制的,而協程的出現,就是為了減少作業系統的開銷,由協程來自己控制任務的切換 協程本質上就是執行緒。既然能夠切換任務,所以執行緒有兩個最基本的功能 一是儲存狀態 二是任務切換 8.8.1 協程的特點 優點 缺點 特點 8.8.2 greenlet 使用gre...