协程的原理:线程是轻量级的进程, 是系统调度的基本单位, 和同一个进程的线程共享资源, 可以迅速切换

协程像是子程序, 在其中可以中断转去执行别的子程序, 适当的时候返回再执行

区别:协程避免了无意义的调度,由此可以提高性能,但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多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() 在超时发生时不会取消可等待对象。