學習一時爽,一直學習一直爽
協程是實作并發程式設計的一種方式。
https://docs.python.org/zh-cn/3/library/asyncio.html
一說并發,你肯定想到了多線程 / 多程序模型,沒錯,多線程 / 多程序,正是解決并發問題的經典模型之一
協程:是單線程下的并發,又稱微線程。
英文名 Coroutine。
協程比線程的機關更小——協程
注意協程這個概念完全是程式員自己想出來的東西,它對于作業系統來說根本不存在。作業系統隻知道程序和線程。
從
import time
def print_num(num):
print("Maoli is printing " + str(num) + " nows" )
time.sleep(1)
print("Maoli prints" + str(num) + " OK")
def main(nums):
for num in nums:
print_num(num)
%time main([i for i in range(1,6)])
Maoli is printing 1 nows
Maoli prints1 OK
Maoli is printing 2 nows
Maoli prints2 OK
Maoli is printing 3 nows
Maoli prints3 OK
Maoli is printing 4 nows
Maoli prints4 OK
Maoli is printing 5 nows
Maoli prints5 OK
Wall time: 5 s
将上面代碼改為協程版
注意 py 版本 3.7 以上
import asyncio
async def print_num(num):
print("Maoli is printing " + str(num) + " nows" )
await asyncio.sleep(1)
print("Maoli prints" + str(num) + " OK")
async def main(nums):
for num in nums:
await print_num(num)
%time asyncio.run(main([i for i in range(1,6)]))
Maoli is printing 1 nows
Maoli prints1 OK
Maoli is printing 2 nows
Maoli prints2 OK
Maoli is printing 3 nows
Maoli prints3 OK
Maoli is printing 4 nows
Maoli prints4 OK
Maoli is printing 5 nows
Maoli prints5 OK
Wall time: 5.01 s
asyncio.run() 函數用來運作最高層級的入口點 "main()" 函數
await 是同步調用等待一個協程。以下代碼段會在等待 1 秒後列印 num,
可等待對象
如果一個對象可以在 await 語句中使用,那麼它就是 可等待 對象
協程中的還一個重要概念,任務(Task)
如果寫一個數字是一個任務,那麼毛利我要完成 5 個任務
毛利我寫個 1-5 都這麼慢,不行,我要加速寫
asyncio.create_task() 函數用來并發運作作為 asyncio 任務 的多個協程。
import asyncio
async def print_num(num):
print("Maoli is printing " + str(num) + " nows" )
await asyncio.sleep(1)
print("Maoli prints" + str(num) + " OK")
async def main(nums):
tasks = [asyncio.create_task(print_num(num)) for num in nums]
for task in tasks:
await task
%time asyncio.run(main([i for i in range(1,6)]))
Maoli is printing 1 nows
Maoli is printing 2 nows
Maoli is printing 3 nows
Maoli is printing 4 nows
Maoli is printing 5 nows
Maoli prints1 OK
Maoli prints3 OK
Maoli prints5 OK
Maoli prints2 OK
Maoli prints4 OK
Wall time: 1.01 s
還可以寫成
await asyncio.gather(*tasks)
這種方法
import asyncio
async def print_num(num):
print("Maoli is printing " + str(num) + " nows" )
await asyncio.sleep(1)
print("Maoli prints" + str(num) + " OK")
async def main(nums):
tasks = [asyncio.create_task(print_num(num)) for num in nums]
await asyncio.gather(*tasks)
%time asyncio.run(main([i for i in range(1,6)]))
*tasks 解包清單,将清單變成了函數的參數;與之對應的是, ** dict 将字典變成了函數的參數。
asyncio 隊列
import asyncio
import random
async def consumer(queue, id):
while True:
val = await queue.get()
print('{} get a val: {}'.format(id, val))
await asyncio.sleep(1)
async def producer(queue, id):
for i in range(5):
val = random.randint(1, 10)
await queue.put(val)
print('{} put a val: {}'.format(id, val))
await asyncio.sleep(1)
async def main():
# 建立隊列
queue = asyncio.Queue()
# 消費者1号
consumer_1 = asyncio.create_task(consumer(queue, 'consumer_1'))
# 消費者2号
consumer_2 = asyncio.create_task(consumer(queue, 'consumer_2'))
# 生産者1号
producer_1 = asyncio.create_task(producer(queue, 'producer_1'))
# 生産者2号
producer_2 = asyncio.create_task(producer(queue, 'producer_2'))
# stop 10秒
await asyncio.sleep(10)
consumer_1.cancel()
consumer_2.cancel()
await asyncio.gather(consumer_1, consumer_2, producer_1, producer_2, return_exceptions=True)
%time asyncio.run(main())