使用Python 3.7進(jìn)行異步編程的入門(mén)例子
Python是一種非常流行的編程語(yǔ)言,它提供了許多強(qiáng)大的功能和庫(kù),使得編寫(xiě)高效的程序變得更加容易。其中一個(gè)非常有用的功能是異步編程,這在處理I/O密集型任務(wù)時(shí)非常有用。在本經(jīng)驗(yàn)中,我們將介紹如何使用P
Python是一種非常流行的編程語(yǔ)言,它提供了許多強(qiáng)大的功能和庫(kù),使得編寫(xiě)高效的程序變得更加容易。其中一個(gè)非常有用的功能是異步編程,這在處理I/O密集型任務(wù)時(shí)非常有用。在本經(jīng)驗(yàn)中,我們將介紹如何使用Python 3.7進(jìn)行異步編程,并提供一個(gè)簡(jiǎn)單的入門(mén)示例。
1. 使用async/await實(shí)現(xiàn)異步編程
首先,我們來(lái)看一個(gè)使用async/await語(yǔ)法實(shí)現(xiàn)的異步程序示例。所有的異步函數(shù)聲明都要加上async關(guān)鍵字。在一個(gè)async函數(shù)內(nèi),異步調(diào)用需要使用await或者其它方式“異步等待”。要運(yùn)行一個(gè)async函數(shù),需要使用來(lái)執(zhí)行。下面是一個(gè)例子:
```
import asyncio
async def my_task(task_id):
print(f"Starting task {task_id}")
await (2)
print(f"Finished task {task_id}")
async def main():
await (
my_task(1),
my_task(2),
my_task(3)
)
if __name__ "__main__":
(main())
```
上述代碼會(huì)輸出以下結(jié)果:
```
Starting task 1
Starting task 2
Starting task 3
Finished task 1
Finished task 2
Finished task 3
```
2. 使用串行方式實(shí)現(xiàn)相同的程序
為了說(shuō)明異步編程的優(yōu)勢(shì),我們可以使用傳統(tǒng)的阻塞式代替異步版本,來(lái)實(shí)現(xiàn)與上述async/await版本完全等價(jià)的串行程序。下面是一個(gè)例子:
```
import time
def my_task(task_id):
print(f"Starting task {task_id}")
(2)
print(f"Finished task {task_id}")
def main():
for i in range(1, 4):
my_task(i)
if __name__ "__main__":
main()
```
上述代碼會(huì)輸出以下結(jié)果:
```
Starting task 1
Finished task 1
Starting task 2
Finished task 2
Starting task 3
Finished task 3
```
3. 對(duì)執(zhí)行代碼進(jìn)行計(jì)時(shí)
如果我們對(duì)異步版本和串行版本的執(zhí)行時(shí)間進(jìn)行比較,就能夠更好地理解異步編程的好處。下面是一個(gè)在代碼中插入計(jì)時(shí)函數(shù)的例子,可以發(fā)現(xiàn)三個(gè)my_task都執(zhí)行完畢總共花了2*36秒。
4. 使用create_task和gather改進(jìn)異步程序
但是,如果使用三個(gè)await按照順序等待,會(huì)浪費(fèi)時(shí)間。第一個(gè)my_task陷入sleep開(kāi)始等待時(shí),完全可以啟動(dòng)第二個(gè)my_task。所以,我們可以使用_task依次創(chuàng)建3個(gè)my_task,并用收集它們。下面是一個(gè)例子:
```
import asyncio
async def my_task(task_id):
print(f"Starting task {task_id}")
await (2)
print(f"Finished task {task_id}")
async def main():
tasks []
for i in range(1, 4):
task _task(my_task(i))
(task)
await (*tasks)
if __name__ "__main__":
(main())
```
上述代碼會(huì)輸出以下結(jié)果:
```
Starting task 1
Starting task 2
Starting task 3
Finished task 1
Finished task 2
Finished task 3
```
5. 異步調(diào)用的工作原理
需要注意的是,async/await機(jī)制并不是多線程或多進(jìn)程等方式,而是單線程實(shí)現(xiàn)的。async/await用于描述控制流何時(shí)切換。一個(gè)異步調(diào)用必須將其awaited。當(dāng)async函數(shù)進(jìn)入等待時(shí),調(diào)用async函數(shù)的一方會(huì)保存現(xiàn)場(chǎng),并層層傳導(dǎo),層層暫停返回。我們可以想象成一棵運(yùn)行樹(shù),從造成等待的葉子節(jié)點(diǎn)(I/O等待,網(wǎng)絡(luò)等待,定時(shí)等待..)逐層返回并凍結(jié)執(zhí)行現(xiàn)場(chǎng),然后接著運(yùn)行其它任務(wù)。雖然只有一個(gè)線程,但是它在多個(gè)async任務(wù)之間按照設(shè)定好的方式interleaving,提升了CPU的繁忙程度和多任務(wù)處理。
6. 注意事項(xiàng)
最后需要注意的是,如果我們沒(méi)有await一個(gè)async調(diào)用,會(huì)有警告提示。這表示該調(diào)用不會(huì)暫停當(dāng)前執(zhí)行現(xiàn)場(chǎng),并在其它地方執(zhí)行代碼。因此,我們應(yīng)該始終await異步調(diào)用,以確保程序正確運(yùn)行。