天天看點

異步程式設計 && 協程asyncio

文章目錄

    • 協程
      • greenlet
      • yield
      • asyncio
      • async / await
    • 協程意義
    • 異步程式設計
      • 事件循環
      • 快速上手
      • await
      • Task對象

協程

協程(Coroutine)不是計算機提供,程式員人為創造

協程也可以稱為微線程, 是一種使用者态的上下文切換技術。就是通過一個線程實作代碼塊互相切換執行。

實作協程方法:

  • greenlet
  • yield
  • asyncio 裝飾器
  • async/await 關鍵字

greenlet

pip install greenlet
           
from greenlet import greenlet

def func1():
    print(1)             # 2. 輸出 1
    gr2.switch()         # 3. 切換到 func2 函數
    print(2)             # 6. 輸出 2
    gr2.switch()         # 7. 切換到 func2 函數,從上一次執行位置向後執行

def func2():
    print(3)             # 4. 輸出 3
    gr1.switch()         # 5. 切換到 func1 函數,從上一次執行位置向後執行
    print(4)             # 8. 輸出 4


gr1 = greenlet(func1)
gr2 = greenlet(func2)

gr1.switch()              # 1. 執行 func1 函數
           

yield

def func1():
    yield 1
    yield from func2()
    yield 2

def func2():
    yield 3
    yield 4

for item in func1():
    print(item)
           

asyncio

python 3.4 之後支援
import asyncio

@asyncio.coroutine
def func1():
    print(1)
    yield from asyncio.sleep(2)
    print(2)


@asyncio.coroutine
def func2():
    print(3)
    yield from asyncio.sleep(2)
    print(4)

tasks = [
    asyncio.ensure_future(func1()),
    asyncio.ensure_future(func2())
]

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
           

遇到 IO 阻塞自動切換

async / await

python 3.5 之後支援
import asyncio

async def func1():
    print(1)
    await asyncio.sleep(2)
    print(2)


async def func2():
    print(3)
    await asyncio.sleep(2)
    print(4)

tasks = [
    asyncio.ensure_future(func1()),
    asyncio.ensure_future(func2())
]

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
           

協程意義

一個線程中遇到 IO 等待時,線程不會傻等,利用空閑時間完成其他任務

異步程式設計

事件循環

事件循環的作用是管理所有的事件,在整個程式運作過程中不斷循環執行,追蹤事件發生的順序将它們放到隊列中,當主線程空閑的時候,調用相應的事件處理者來處理事件

快速上手

  • 協程函數:async def 函數名
  • 協程對象:執行 協程函數() 得到協程對象
async def func():
    pass

# 執行協程函數得到協程對象,函數内部代碼不會執行
result = func()
           
# 想要運作協程函數内部代碼,必須要将協程對象交給事件循環處理

async def func():
    print('test')

res = func()

loop = asyncio.get_event_loop()
loop.run_until_complete(res)

# py3.7+
asyncio.run(res)
           

await

await + 可等待的對象 (協程對象, Future, Task對象) IO等待

async def test():
    print('test')
    res = await asyncio.sleep(2)
           

Task對象

Tasks 用于并發排程協程,通過

asyncio.create_task(協程對象)

的方式建立 Task 對象,這樣可以讓協程加入事件循環中等到被排程執行

# Example 1
async def test():
    print('test satart...')
    await asyncio.sleep(2)

async def main():
    print('start...')
    task1 = asyncio.create_task(test())
    task2 = asyncio.create_task(test())
    await task1
    await task2

asyncio.run(main())

# start...
# test satart...
# test satart...

# sleep 2
           
# Example 2
async def test():
    print('test satart...')
    await asyncio.sleep(1)
    return '1'

async def main():
    tasks = [
        asyncio.create_task(test()),
        asyncio.create_task(test()),
    ]
    await asyncio.wait(tasks)
    

asyncio.run(main())