Python中的非同步IO和協程

2021-07-25 15:47:36 字數 4472 閱讀 5320

python中的協程是通過「生成器(generator)」的概念實現的。這裡引用廖雪峰python教程中的例子,並做一點修改和「裝飾」:

def

consumer

(): print("[consumer] init consumer ......")

r = "init ok"

# 初始化返回結果,並在啟動消費者時,返回給生產者

while

true:

n = yield r # 消費者通過yield接收生產者的訊息,同時返給其結果

print("[consumer] conusme n = %s, r = %s" % (n, r))

r = "consume %s ok" % n # 消費者消費結果,下個迴圈返回給生產者

defproduce

(c):

# 定義生產者,此時的 c 為乙個生成器

print("[producer] init producer ......")

r = c.send(none) # 啟動消費者生成器,同時第一次接收返回結果

print("[producer] start consumer, return %s" % r)

n = 0

while n < 5:

n += 1

print("[producer] while, producing %s ......" % n)

r = c.send(n) # 向消費者傳送訊息並準備接收結果。此時會切換到消費者執行

print("[producer] consumer return: %s" % r)

c.close() # 關閉消費者生成器

print("[producer] close producer ......")

produce(consumer())輸出結果:[producer] init producer ......

[consumer] init consumer ......

[producer] start consumer, return init ok

[producer] while, producing 1 ......

[consumer] conusme n = 1, r = init ok

[producer] consumer return: consume 1 ok

[producer] while, producing 2 ......

[consumer] conusme n = 2, r = consume 1 ok

[producer] consumer return: consume 2 ok

[producer] while, producing 3 ......

[consumer] conusme n = 3, r = consume 2 ok

[producer] consumer return: consume 3 ok

[producer] while, producing 4 ......

[consumer] conusme n = 4, r = consume 3 ok

[producer] consumer return: consume 4 ok

[producer] while, producing 5 ......

[consumer] conusme n = 5, r = consume 4 ok

[producer] consumer return: consume 5 ok

[producer] close producer ......

**中新增了很詳細的print語句和注釋,幫助大家更好的理解。這裡刪除了源**consumer中的「return」語句。如果還是不太明白,可以在編輯器中進行debug除錯,一步步跟蹤程式的執行過程。

關於非同步io,在python3.4中可以使用asyncio標準庫。該標準庫支援乙個時間迴圈模型(eventloop),我們宣告協程,然後將其加入到eventloop中,即可實現非同步io。

python中也有乙個關於非同步io的很經典的helloworld程式(同樣參考於廖雪峰教程):

# 非同步io例子:適配python3.4,使用asyncio庫

@asyncio.coroutine

defhello

(index):

# 通過裝飾器asyncio.coroutine定義協程

print('hello world! index=%s, thread=%s' % (index, threading.currentthread()))

yield

from asyncio.sleep(1) # 模擬io任務

print('hello again! index=%s, thread=%s' % (index, threading.currentthread()))

loop = asyncio.get_event_loop() # 得到乙個事件迴圈模型

tasks = [hello(1), hello(2)] # 初始化任務列表

loop.run_until_complete(asyncio.wait(tasks)) # 執行任務

loop.close() # 關閉事件迴圈列表

同樣這裡的**新增了注釋,並增加了index引數。輸出currentthread的目的是演示當前程式都是在乙個執行緒中執行的。返回結果如下:

hello world! index=1, thread=<_mainthread(mainthread, started 14816)>

hello world! index=2, thread=<_mainthread(mainthread, started 14816)>

hello again! index=1, thread=<_mainthread(mainthread, started 14816)>

hello again! index=2, thread=<_mainthread(mainthread, started 14816)>

在python3.5中引入了關於非同步io的新語法:async和await關鍵字。

# 非同步io例子:適配python3.5,使用async和await關鍵字

async

defhello

(index):

# 通過關鍵字async定義協程

print('hello world! index=%s, thread=%s' % (index, threading.currentthread()))

await asyncio.sleep(1) # 模擬io任務

print('hello again! index=%s, thread=%s' % (index, threading.currentthread()))

loop = asyncio.get_event_loop() # 得到乙個事件迴圈模型

tasks = [hello(1), hello(2)] # 初始化任務列表

loop.run_until_complete(asyncio.wait(tasks)) # 執行任務

loop.close() # 關閉事件迴圈列表

從**中可以看出,使用async代替@asyncio.coroutine,使用await代替yield from,使得協程**更加簡潔易懂。

非同步io特別適合爬蟲的工作,因為爬蟲中所有的請求都屬於io密集型任務,想得到比較好的爬蟲效率,使用協程很重要。關於http非同步請求,建議使用 aiohttp庫 ,乙個非同步的http客戶端/伺服器框架。這裡舉個例子,更多用法可以參考其官方文件。

loop = asyncio.get_event_loop() # 得到乙個事件迴圈模型

tasks = [ # 初始化任務列表

get(""),

get(""),

get("")

]loop.run_until_complete(asyncio.wait(tasks)) # 執行任務

loop.close() # 關閉事件迴圈列表

非同步io和協程

常見的非同步io模組asyncio gevent twisted tornado 核心技術為select 和協程 非同步io請求的本質則是 非阻塞socket io多路復用 協程在這裡不是乙個必須使用的技術,在使用select 事件驅動迴圈本身就可以達到單執行緒非同步的效果 io協程在遇到阻塞時進行...

非同步I O 協程

什麼是協程呢?協程 coroutines 是一種比執行緒更加輕量級的存在,正如乙個程序可以擁有多個執行緒一樣,乙個執行緒可以擁有多個協程。協程不是被作業系統核心所管理的,而是完全由程式所控制,也就是在使用者態執行。這樣帶來的好處是效能大幅度的提公升,因為不會像執行緒切換那樣消耗資源。協程不是程序也不...

Python的執行緒 程序和協程

程序 乙個程序就是乙個正在執行的程式,它是計cpu分配資源的最小單位。每個程序都有自己獨立的記憶體空間。能同時執行的程序數最多不超過核心數,也就是每個核心 同一時刻只能執行乙個程序。那麼多程序就是能 同時 執行多個程序 比如同時聽 和寫 這裡的 同時 可以指cpu通過極快地在程序間來回切換來實現,所...