問題起源:循環(huán)體內(nèi)無法實(shí)現(xiàn)異步。
Python使用異步模塊Asyncio實(shí)現(xiàn)多線程并發(fā),一般方式是:
async def func():
# code...
async def main():
await(func())
if __name__ =='__main__':
asyncio.run(main())
但實(shí)驗(yàn)過程中有個(gè)需求,是讓循環(huán)體的每次循環(huán)都作為一個(gè)并發(fā)線程產(chǎn)生并發(fā)。
這種情況下,每次循環(huán)使用await調(diào)用異步函數(shù),無法實(shí)現(xiàn)需求中的并發(fā)需求。
asyncio程序如下:
import time
import asyncio
async def hello():
await asyncio.sleep(1)
print('Hello World:%s' % time.time())
async def main():
start = time.time()
for i in range(5):
await(hello())
print("use time: %f s" % (time.time()-start))
if __name__ =='__main__':
asyncio.run(main())
程序結(jié)果:
Hello World:1608368438.992576
Hello World:1608368439.9939594
Hello World:1608368440.9950461
Hello World:1608368441.9971309
Hello World:1608368443.00034
use time: 5.008629 s
程序運(yùn)行時(shí)間是5秒,意味著并未達(dá)到異步的效果。
原因:整個(gè)for循環(huán)體是一個(gè)協(xié)程,協(xié)程切換時(shí)會(huì)掛起整個(gè)main協(xié)程。
解決辦法:使用asyncio.gather()
asyncio.gather()需要輸入一個(gè)任務(wù)列表,gather會(huì)劃分任務(wù),并分組執(zhí)行,因此可以應(yīng)對for循環(huán)體內(nèi)的異步。
完善后的代碼:
import time
import asyncio
async def hello():
await asyncio.sleep(1)
print('Hello World:%s' % time.time())
async def main():
tasks=[]
for i in range(5):
tasks.append(hello())
await asyncio.gather(*tasks)
if __name__ =='__main__':
asyncio.run(main())
程序運(yùn)行結(jié)果:
Hello World:1608368546.8756351
Hello World:1608368546.8756351
Hello World:1608368546.8756351
Hello World:1608368546.8756351
Hello World:1608368546.8756351
use time: 1.002837 s
程序運(yùn)行時(shí)間是1秒,說明已經(jīng)達(dá)到異步效果。