日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

python异步编程之asyncio初识

發(fā)布時間:2023/12/31 python 40 coder
生活随笔 收集整理的這篇文章主要介紹了 python异步编程之asyncio初识 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

async await介紹

用asyncio提供的@asyncio.coroutine可以把一個生成器標記為協(xié)程類型,然后在協(xié)程內(nèi)部用yield from 等待IO操作,讓出cpu執(zhí)行權(quán)。
然而異步的關(guān)鍵字yield 和 yield from畢竟是復(fù)用生成器關(guān)鍵字,兩者在概念上糾纏不清,所以從Python 3.5開始引入了新的語法async和await替換yield 和 yield from,讓協(xié)程的代碼更易懂。
簡單來說,可以這樣理解:

  • async 替換 @asyncio.coroutine:標識一個函數(shù)為異步函數(shù)
  • await 替換 yield from:標識等待IO操作,讓出CPU執(zhí)行權(quán)

async 實現(xiàn)協(xié)程示例

由于協(xié)程在各個python版本中有細微差異,本篇以python3.10為例

import asyncio


async def coro1():
    print("start coro1")
    await asyncio.sleep(2)
    print("end coro1")


async def coro2():
    print("start coro2")
    await asyncio.sleep(1)
    print("end coro2")


# 創(chuàng)建事件循環(huán)
loop = asyncio.get_event_loop()


# 創(chuàng)建任務(wù)
task1 = loop.create_task(coro1())
task2 = loop.create_task(coro2())

# 運行協(xié)程
loop.run_until_complete(asyncio.gather(task1, task2))

# 關(guān)閉事件循環(huán)
loop.close()

輸出結(jié)果:

start coro1
start coro2
end coro2
end coro1

代碼邏輯:

  1. 創(chuàng)建一個事件循環(huán)
  2. 將兩個異步函數(shù)coro1,coro2封裝成兩個任務(wù)task1,task2
  3. 用asyncio.gather將兩個任務(wù)組合到一起,并發(fā)執(zhí)行task1,task2
  4. 先執(zhí)行task1,遇到IO切換到task2
  5. 執(zhí)行task2,遇到IO切換,但此時沒有等待執(zhí)行的任務(wù),cpu為空
  6. task2執(zhí)行完成,task1執(zhí)行完成

從示例代碼可以看出,協(xié)程的幾個關(guān)鍵要素:

  1. 事件循環(huán)
  2. 協(xié)程函數(shù)定義
  3. 可等待對象
  4. 并發(fā)執(zhí)行

協(xié)程基本原理

組成協(xié)程最重要的因素就是事件循環(huán)任務(wù)。

  • 任務(wù)就是一個對象,包括執(zhí)行的代碼,執(zhí)行完成、失敗等狀態(tài)以及返回結(jié)果,任務(wù)中通常會有IO切換。
  • 事件循環(huán),可以把它當(dāng)做是一個while循環(huán)。while循環(huán)在周期性的運行并執(zhí)行一些任務(wù),所有任務(wù)執(zhí)行完成會關(guān)閉循環(huán)。

偽代碼示例如下:

任務(wù)列表 = [ 任務(wù)1, 任務(wù)2, 任務(wù)3,... ]

while True:
    可執(zhí)行的任務(wù)列表,已完成的任務(wù)列表 = 去任務(wù)列表中檢查所有的任務(wù),將'可執(zhí)行'和'已完成'的任務(wù)返回
    
    for 就緒任務(wù) in 已準備就緒的任務(wù)列表:
        執(zhí)行已就緒的任務(wù)
        
    for 已完成的任務(wù) in 已完成的任務(wù)列表:
        在任務(wù)列表中移除 已完成的任務(wù)

    如果 任務(wù)列表 中的任務(wù)都已完成,則終止循環(huán)

獲取和創(chuàng)建事件循環(huán):loop = asyncio.get_event_loop()
驅(qū)動事件循環(huán)運行:loop.run_until_complete(asyncio.gather(task1, task2))
事件循環(huán)過程:
事件循環(huán)中執(zhí)行任務(wù),當(dāng)執(zhí)行到某一個任務(wù)時遇到IO時,協(xié)程會讓出CPU給第二個任務(wù)執(zhí)行,第二個任務(wù)中遇到IO再次讓出CPU,直到所有任務(wù)完成。這就是協(xié)程并發(fā)性能好的一個關(guān)鍵能力:遇到IO切換任務(wù)執(zhí)行,避免了程序等待IO完成再執(zhí)行的耗時。

為什么協(xié)程在IO密集時性能較好

很多人可能會疑問,多線程遇到IO也會切換,為什么協(xié)程比線程性能好呢?
簡單來是三點:

  1. 協(xié)程更輕量級,切換需要恢復(fù)的上線文很少,所以比線程更快速
  2. 線程切換CPU是搶占的,協(xié)程是主動讓出的,協(xié)程對CPU的使用更充分
  3. 協(xié)程更輕量級,啟動線程需要的內(nèi)存資源比協(xié)程更多

示例代碼的高級api實現(xiàn)

示例代碼中使用了asyncio.get_event_loop()loop.run_until_complete()等代碼,這些其實asyncio包的低級API,是為了展示底層原理而使用的。通常更推薦高級APIasyncio.run()實現(xiàn)協(xié)程并發(fā)。

import asyncio


async def coro1():
    print("start coro1")
    await asyncio.sleep(2)
    print("end coro1")


async def coro2():
    print("start coro2")
    await asyncio.sleep(1)
    print("end coro2")


async def main():
    task1 = asyncio.create_task(coro1())
    task2 = asyncio.create_task(coro2())
    await asyncio.gather(task1, task2)


asyncio.run(main())

run() 從功能上等價于以下低階API

loop = asyncio.get_event_loop()
task = loop.create_task(coro())
loop.run_until_complete(task)

連載一系列關(guān)于python異步編程的文章。包括同異步框架性能對比、異步事情驅(qū)動原理等。歡迎關(guān)注微信公眾號第一時間接收文章。

總結(jié)

以上是生活随笔為你收集整理的python异步编程之asyncio初识的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。