协程的原理:线程是轻量级的进程, 是系统调度的基本单位, 和同一个进程的线程共享资源, 可以迅速切换
协程像是子程序, 在其中可以中断转去执行别的子程序, 适当的时候返回再执行
区别:协程避免了无意义的调度,由此可以提高性能,但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力。
await 只能接coroutin, 不是则需要用create_task()转换
不用time.sleep()是因为这不是阻塞, 而是推迟线程的运行
可等待对象:可以在await后用的对象, 有task, future和conroutin. task是被包装过的conroutin, future是底层的可等待对象, 表示一个异步操作的最终结果
没有返回值的阻塞:
async def cost():
await asyncio.sleep(3)
async def main():
task = asyncio.create_task(cost())
await task
asyncio.run(main())
有返回值的阻塞:
async def cost():
await asyncio.sleep(3)
return 'done'
async def main():
task = asyncio.creat_task(cost())
await task
print(task.result())
asyncio.run(main())
-----result-----
done
协起程来:
async def cost(x):
print(f'cont({x}) start')
await asyncio.sleep(x)
print(f'cost({x}) end')
return x
async def main():
task3 = asyncio.create_task(cost(3))
task1 = asyncio.create_task(cost(1))
await task3
await task1
print(f'two task finished, task3 costs {task3.result()}, task1 costs {task1.result()}')
asyncio.run(main())
-----result-----
cont(3) start
cont(1) start
cost(1) end
cost(3) end
two task finished, task3 costs 3, task1 costs 1
协不起来:
async def cost(x):
print(f'cont({x}) start')
await asyncio.sleep(x)
print(f'cost({x}) end')
return x
async def main():
# task3 = asyncio.create_task(cost(3))
# task1 = asyncio.create_task(cost(1))
r3 = await cost(3)
r1 = await cost(1)
print(f'two task finished, task3 costs {r3}, task1 costs {r1}')
asyncio.run(main())
-----result-----
cont(3) start
cost(3) end
cont(1) start
cost(1) end
two task finished, task3 costs 3, task1 costs 1
常用函数:
asyncio.gather(*aws,loop=None,return_exceptions=False)
并发执行序列中的可等待对象, 返回任务返回值的列表.
如果所有可等待对象都成功完成,结果将是一个由所有返回值聚合而成的列表。结果值的顺序与 aws 中可等待对象的顺序一致。
如果 return_exceptions 为 False (默认),所引发的首个异常会立即传播给等待 gather() 的任务。aws 序列中的其他可等待对象 不会被取消 并将继续运行。
如果 return_exceptions 为 True,异常会和成功的结果一样处理,并聚合至结果列表。
如果 gather() 被取消,所有被提交 (尚未完成) 的可等待对象也会 被取消。
如果 aws 序列中的任一 Task 或 Future 对象 被取消,它将被当作引发了 gather() 调用 不会 被取消。这是为了防止一个已提交的 Task/Future 被取消导致其他 Tasks/Future 也被取消。
async def cost(x):
await asyncio.sleep(x)
async def main():
task = [asyncio.create_task(cost(i)) for i in range(3)]
await task[0]
await task[1]
await task[2]
---等价于---
asynic def main()"
task = [cost(i) for i in range(3)]
await asyncio.gather(*task)
asyncio.wait_for(aw, timeout, *,)
等待 aw 可等待对象 完成,指定 timeout 秒数后超时。
如果 aw 是一个协程,它将自动作为任务加入日程。
timeout 可以为 None,也可以为 float 或 int 型数值表示的等待秒数。如果 timeout 为 None,则等待直到完成。
要避免任务
函数将等待直到目标对象确实被取消,所以总等待时间可能超过 timeout 指定的秒数。
如果等待被取消,则 aw 指定的对象也会被取消。
asyncio.wait(aws, *, timeout=None, return_when=ALL_COMPLETED)
并发运行 aws 指定的 可等待对象 并阻塞线程直到满足 return_when 指定的条件。
如果 aws 中的某个可等待对象为协程,它将自动作为任务加入日程。直接向 wait() 传入协程对象已弃用,因为这会导致 令人迷惑的行为。
返回两个 Task/Future 集合: (done, pending)。
用法:
done, pending = await asyncio.wait(aws)
loop 参数已弃用,计划在 Python 3.10 中移除。
如指定 timeout (float 或 int 类型) 则它将被用于控制返回之前等待的最长秒数。
请注意此函数不会引发
return_when 指定此函数应在何时返回。它必须为以下常数之一:
常数描述FIRST_COMPLETED函数将在任意可等待对象结束或取消时返回。FIRST_EXCEPTION函数将在任意可等待对象因引发异常而结束时返回。当没有引发任何异常时它就相当于ALL_COMPLETED。ALL_COMPLETED函数将在所有可等待对象结束或取消时返回。
与 wait() 在超时发生时不会取消可等待对象。