Python 3.5添加了async和await这两个关键字,分别用来替换asyncio.coroutine和yield from。自此,协程成为新的语法,而不再是一种生成器类型了。
事件循环与协程的引入,可以极大提高高负载下程序的I/O性能。除此之外还增加了async with(异步上下文管理)、async for(异步迭代器)语法。特别说的是,在Python 3.6里面终于可以用异步生成器了!
1.给一个函数添加了async关键字,就会把它变成一个异步函数。
2.每个线程有一个事件循环,主线程调用asyncio.get_event_loop时会创建事件循环,你需要把异步的任务丢给这个循环的run_until_complete方法,事件循环会安排协同程序的执行。和方法名字一样,异步的任务完成方法才会就执行完成了。
3.为了在asyncio中使用concurrent.futures的执行器,我这用到了run_in_executor,它可以接收要同步执行的任务。
4.给task设置num属性,是因为后面的completed中的Future对象只包含结果,但是我们并不知道num是什么,所以hack了下,之后的例子中会有其他的方案,本文是给大家提供各种解题的思路,在合适的场景还是有用处的。
5.await asyncio.wait(blocking_tasks)就是协同的执行那些同步的任务,直到完成。
6.最后根据num找到和执行结果的对应关系,排序然后打印结果。
async/await是Python提供的异步编程API,而asyncio只是一个利用 async/await API进行异步编程的框架
现存的一些库其实并不能原生的支持asyncio(因为会发生阻塞或者功能不可用),比如requests,如果要写爬虫,配合asyncio的应该用aiohttp,其他的如数据库驱动等各种Python对应的库也都得使用对应的aioXXX版本了
简单的说,进程/线程是操作系统充当了EventLoop调度,而协程是自己用epoll进行调度。
协程是异步非阻塞的另外一种展现形式。Golang,Erlang,Lua协程都是这个模型。
协程之间的切换,往往是用户通过代码来显式指定的(跟各种 callback 类似),不需要内核参与,可以很方便的实现异步。
协程本质上也是异步非阻塞技术,它是将事件回调进行了包装,让程序员看不到里面的事件循环。程序员就像写阻塞代码一样简单。比如调用 client->recv() 等待接收数据时,就像阻塞代码一样写。实际上是底层库在执行recv时悄悄保存了一个状态,比如代码行数,局部变量的值。然后就跳回到EventLoop中了。什么时候真的数据到来时,它再把刚才保存的代码行数,局部变量值取出来,又开始继续执行。