894 阅读 · 2023年8月24日 11:01 更新 · 作者:clannadhh
Python3.x系列的协程有很多不同的地方,这里介绍下主要的:
import asyncio
@asyncio.coroutine
def get_body(i):
print(f'start{i}')
yield from asyncio.sleep(1)
print(f'end{i}')
loop = asyncio.get_event_loop()
tasks = [get_body(i) for i in range(5)]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
输出结果:
start4
start0
start1
start3
start2
end4
end0
end1
end3
end2
它的效果是和Gevent一样的,遇到IO操作的时候,自动切换上下文。
不同的是,它对tasks的操作:task先把这个5个参数不同的函数全部加载进来,然后执行任务,任务执行是无序的。
@asyncio.coroutine把一个generator标记为coroutine类型,然后把这个coroutine扔到eventloop中执行
yield from 语法让我们方便的调用另一个generator。由于asyncio.sleep()也是一个coroutine,线程不会等待,直接中断执行下一个消息循环。当asyncio.sleep()返回时,线程可以从yield from拿到返回值(此处是None),然后接着执行下一行语句。
2、async/await
在Python3.5的时候,asyncio添加了两个关键字aysnc和await,让coroutine语法更简洁。
async关键字可以将一个函数修饰为协程对象,await关键字可以将需要耗时的操作挂起,一般多是IO操作。
它们是针对coroutine的新语法,只需要把@asyncio.coroutine替换为async、yield from替换为await。
import asyncio
async def get_body(i):
print(f'start{i}')
await asyncio.sleep(1)
print(f'end{i}')
loop = asyncio.get_event_loop()
tasks = [get_body(i) for i in range(5)]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
运行结果:
start3
start4
start1
start0
start2
end3
end4
end1
end0
end2
Python3.7以后的版本使用asyncio.run即可。此函数总是会创建一个新的事件循环并在结束时关闭之。它应当被用作 asyncio 程序的主入口点,理想情况下应当只被调用一次。
import asyncio
async def work(x): # 通过async关键字定义一个协程
for _ in range(3):
print('Work {} is running ..'.format(x))
coroutine_1 = work(1) # 协程是一个对象,不能直接运行
# 方式一:
loop = asyncio.get_event_loop() # 创建一个事件循环
result = loop.run_until_complete(coroutine_1) # 将协程对象加入到事件循环中,并执行
print(result) # 协程对象并没有返回结果,打印None
# 方式二:
# asyncio.run(coroutine_1) #创建一个新的事件循环,并以coroutine_1为程序的主入口,执行完毕后关闭事件循环
使用asyncio实现的协程的一些特性:
async修饰返回的协程对象,不能直接执行,需要添加到事件循环event_loop中执行。