淺談Python協(xié)程asyncio
一、協(xié)程
官方描述;
協(xié)程是子例程的更一般形式。 子例程可以在某一點(diǎn)進(jìn)入并在另一點(diǎn)退出。 協(xié)程則可以在許多不同的點(diǎn)上進(jìn)入、退出和恢復(fù)。 它們可通過(guò) async def 語(yǔ)句來(lái)實(shí)現(xiàn)。 參見(jiàn) PEP 492。
- 協(xié)程不是計(jì)算機(jī)內(nèi)部提供的,不像進(jìn)程、線程,由電腦本身提供,它是由程序員人為創(chuàng)造的, 實(shí)現(xiàn)函數(shù)異步執(zhí)行。
- 協(xié)程(Coroutine),也可以被稱(chēng)為微線程,是一種用戶太內(nèi)的上下文切換技術(shù),其實(shí)就是通過(guò)一個(gè)線程實(shí)現(xiàn)代碼塊相互切換執(zhí)行??瓷先ハ褡映绦?,但執(zhí)行過(guò)程中,在子程序內(nèi)部可中斷,然后轉(zhuǎn)而執(zhí)行別的子程序,在適當(dāng)?shù)臅r(shí)候再返回來(lái)接著執(zhí)行。例如:
# 需要python3.7+
import asyncio
async def main():
print('hello')
await asyncio.sleep(1)
print('world')
asyncio.run(main())
# 打印 "hello",等待 1 秒,再打印 "world"
注意:簡(jiǎn)單地調(diào)用一個(gè)協(xié)程并不會(huì)使其被調(diào)度執(zhí)行,
直接main() 調(diào)用會(huì)有問(wèn)題:
RuntimeWarning: coroutine 'main' was never awaited main() RuntimeWarning: Enable tracemalloc to get the object allocation traceback
def func1():
print(1)
...
print(2)
def func2():
print(3)
...
print(4)
func1()
func2()
# 結(jié)果:1 2 3 4
實(shí)現(xiàn)協(xié)程的方法:
- greenlet,早期模塊【不建議使用】
- yield關(guān)鍵字,它是python的生成器,具有保存狀態(tài),切換到其他函數(shù)去執(zhí)行,再切換回原函數(shù)的功能。
- asyncio裝飾器(python3.4引入)
- async、await 關(guān)鍵字(python3.5)【推薦使用】
1.1 greenlet實(shí)現(xiàn)協(xié)程
# 第三方模塊,因此需要安裝 pip install greenlet
from greenlet import greenlet
def func1():
print(1)
gr2.switch()
print(2)
gr2.switch()
def func2():
print(3)
gr1.switch()
print(4)
gr1 = greenlet(func1)
gr2 = greenlet(func2)
gr1.switch()
# 結(jié)果:1 3 2 4
1.2 yield關(guān)鍵字
def func1():
yield 1
yield from func2()
yield 2
def func2():
yield 3
yield 4
f1 = func1()
for item in f1:
print(item)
# 結(jié)果:1 3 2 4
1.3 asynico裝飾器
python3.4 及之后版本支持
DeprecationWarning: “@coroutine” decorator is deprecated since Python 3.8, use “async def”
翻譯:@coroutine"裝飾器自Python 3.8起已棄用,請(qǐng)使用"async def"代替
所以這個(gè)也不支持。
import asyncio
@asyncio.coroutine
def func1():
print(1)
yield from asyncio.sleep(2) # 遇到IO耗時(shí)操作,自動(dòng)切換到tasks中其他任務(wù),比如:網(wǎng)絡(luò)IO,下載圖片
print(2)
@asyncio.coroutine
def func2():
print(3)
yield from asyncio.sleep(2) # 遇到IO耗時(shí)操作,自動(dòng)切換到tasks中其他任務(wù),比如:網(wǎng)絡(luò)IO,下載圖片
print(4)
tasks = [
asyncio.ensure_future(func1()),
asyncio.ensure_future(func2())
]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
# 結(jié)果: 1 3 2 4
1.4 async & await 關(guān)鍵字
import asyncio
async def func1():
print(1)
await asyncio.sleep(2) # 遇到IO耗時(shí)操作,自動(dòng)切換到tasks中其他任務(wù),比如:網(wǎng)絡(luò)IO,下載圖片
print(2)
async def func2():
print(3)
await asyncio.sleep(2) # 遇到IO耗時(shí)操作,自動(dòng)切換到tasks中其他任務(wù),比如:網(wǎng)絡(luò)IO,下載圖片
print(4)
tasks = [
asyncio.ensure_future(func1()),
asyncio.ensure_future(func2())
]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
二、協(xié)程的意義
充分利用線程。在一個(gè)線程中如果遇到IO等待時(shí)間線程不會(huì)一直等待,利用空閑時(shí)間再去干點(diǎn)其他事情。
以下載三張圖片為例:
普通方式(同步)下載:
import time
import requests
def download_image(url, img_name):
print("開(kāi)始下載:", url)
# 發(fā)送網(wǎng)絡(luò)請(qǐng)求,下載圖片
response = requests.get(url)
print("下載完成")
# 圖片保存到本地文件
file_name = str(img_name) + '.png'
with open(file_name, mode='wb') as file:
file.write(response.content)
if __name__ == '__main__':
start = time.time()
url_list = [
'https://tse4-mm.cn.bing.net/th/id/OIP.866vRxQ8QvyDsrUuXiu7qwHaNK?w=182&h=324&c=7&o=5&pid=1.7',
'https://tse2-mm.cn.bing.net/th/id/OIP.HUcWtoYPG-z2pu4ityajbAHaKQ?w=182&h=252&c=7&o=5&pid=1.7',
'https://tse2-mm.cn.bing.net/th/id/OIP.MvncR0-Pt9hVxKTdrvD9dAHaNK?w=182&h=324&c=7&o=5&pid=1.7',
'https://tse1-mm.cn.bing.net/th/id/OIP._nGloaeMWbL7NB7Lp6SnXQHaLH?w=182&h=273&c=7&o=5&pid=1.7',
]
img_name = 1
for item in url_list:
download_image(item, img_name)
img_name += 1
end = time.time()
print(end - start)
# 最終時(shí)間:7.25s
協(xié)程方式(異步)下載:
import aiohttp
import asyncio
import time
async def fetch(session, url):
print("發(fā)送請(qǐng)求:", url)
async with session.get(url, verify_ssl=False) as response:
content = await response.content.read()
file_name = url.rsplit('_')[-1]
# print(file_name)
with open(file_name, mode='wb') as file_object:
file_object.write(content)
print("下載完成")
async def main():
async with aiohttp.ClientSession() as session:
url_list = [
'https://www3.autoimg.cn/newsdfs/g26/M02/35/A9/120x90_0_autohomecar__ChsEe12AXQ6AOOH_AAFocMs8nzU621.jpg',
'https://www3.autoimg.cn/newsdfs/g26/M02/35/A9/120x90_0_autohomecar__ChsEe12AXQ6AOOH_AAFocMs8nzU621.jpg',
'https://www3.autoimg.cn/newsdfs/g26/M02/35/A9/120x90_0_autohomecar__ChsEe12AXQ6AOOH_AAFocMs8nzU621.jpg',
'https://www3.autoimg.cn/newsdfs/g26/M02/35/A9/120x90_0_autohomecar__ChsEe12AXQ6AOOH_AAFocMs8nzU621.jpg',
]
tasks = [asyncio.ensure_future(fetch(session, url)) for url in url_list]
await asyncio.wait(tasks)
if __name__ == '__main__':
start = time.time()
asyncio.get_event_loop().run_until_complete(main())
end = time.time()
print(end - start)
# 結(jié)果:0.05s
到此這篇關(guān)于淺談Python協(xié)程的文章就介紹到這了,更多相關(guān)Python協(xié)程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python 新建文件夾與復(fù)制文件夾內(nèi)所有內(nèi)容的方法
今天小編就為大家分享一篇Python 新建文件夾與復(fù)制文件夾內(nèi)所有內(nèi)容的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-10-10
Python和Plotly實(shí)現(xiàn)3D圖形繪制
在當(dāng)今的數(shù)據(jù)分析和可視化領(lǐng)域,Python已經(jīng)成為一種不可或缺的工具,Plotly作為一種高級(jí)的繪圖庫(kù),特別擅長(zhǎng)于創(chuàng)建交互式和3D圖形,下面我們就來(lái)看看Python如何利用Plotly實(shí)現(xiàn)3D圖形繪制吧2024-11-11
使用python serial 獲取所有的串口名稱(chēng)的實(shí)例
今天小編就為大家分享一篇使用python serial 獲取所有的串口名稱(chēng)的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-07-07
Python基礎(chǔ)入門(mén)之魔法方法與異常處理
在python中,所有以“__"雙下劃線包起來(lái)的方法,都統(tǒng)稱(chēng)為魔法方法,下面這篇文章主要給大家介紹了關(guān)于Python基礎(chǔ)入門(mén)之魔法方法與異常處理的相關(guān)資料,需要的朋友可以參考下2021-11-11
Python實(shí)現(xiàn)遞歸遍歷文件夾并刪除文件
本文給大家匯總了3個(gè)Python實(shí)現(xiàn)遍歷文件夾并刪除的代碼,主要是給大家分享下這3種方法的實(shí)現(xiàn)思路,有需要的小伙伴可以參考下2016-04-04
Python讀寫(xiě)二進(jìn)制文件的實(shí)現(xiàn)
本文主要介紹了Python讀寫(xiě)二進(jìn)制文件的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
了解一下python內(nèi)建模塊collections
這篇文章主要介紹了Python內(nèi)建模塊——collections的相關(guān)資料,幫助大家更好的理解和使用python,感興趣的朋友可以了解下2020-09-09
python爬蟲(chóng)項(xiàng)目設(shè)置一個(gè)中斷重連的程序的實(shí)現(xiàn)
這篇文章主要介紹了python爬蟲(chóng)項(xiàng)目設(shè)置一個(gè)中斷重連的程序的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07

