Python协程还不理解?请收下这份超详细的异步编程教程( 四 )


await 的作用就是等待当前的协程运行结束之后再继续进行下面代码 。因为我们执行 result1 的时间很短,所以在表面上看 result1 和 result2 是一起执行的 。这就是 await 的作用 。等待一个协程的执行完毕,如果有返回结果,那么就会接收到协程的返回结果,通过使用 return 可以返回协程的一个结果,这个和同步函数的 return 使用方法一样 。
2.7 并发的执行任务一系列的协程可以通过 await 链式调用,但是有的时候我们需要在一个协程里等待多个协程,比如我们在一个协程里等待 1000 个异步网络请求,对于访问次序没有要求的时候,就可以使用关键字 wait 来解决了 。wait 可以暂停一个协程,直到后台操作完成 。
Task 的使用

Python协程还不理解?请收下这份超详细的异步编程教程

文章插图
 
输出:
Python协程还不理解?请收下这份超详细的异步编程教程

文章插图
 
如果运行的话会发现首先会打印 10 次数字,但是并不是顺序执行的,这也说明 asyncio.wait 并发执行的时候是乱序的 。如果想保证顺序只要使用 gather 把 task 写成解包的形式就行了,也就是上面的注释部分的代码 。
2.8 如何在协程中使用普通的函数呢?我们知道在普通函数中调用普通函数之间,函数名加括号即可,像下面这样:
Python协程还不理解?请收下这份超详细的异步编程教程

文章插图
 
那么在协程中如何使用一个普通函数呢?在协程中可以通过一些方法去调用普通的函数 。可以使用的关键字有 call_soon 等 。
2.9 call_soon可以通过字面意思理解调用立即返回 。下面来看一下具体的使用例子:
Python协程还不理解?请收下这份超详细的异步编程教程

文章插图
 
输出结果:
Python协程还不理解?请收下这份超详细的异步编程教程

文章插图
 
通过输出结果我们可以发现我们在协程中成功调用了一个普通函数,顺序地打印了 1 和 2 。
看过这些例子之后,也许你就有疑问了,协程没有缺点的么?
3. 协程的缺点同样的总结下大概以下 2 点 。
3.1 无法使用 CPU 的多核协程的本质是个单线程,它不能同时用上单个 CPU 的多个核,协程需要和进程配合才能运行在多 CPU 上 。当然我们日常所编写的绝大部分应用都没有这个必要,就比如网络爬虫来说,限制爬虫的速度还有其他的因素,比如网站并发量、网速等问题都会是爬虫速度限制的因素 。除非做一些密集型应用,这个时候才可能会用到多进程和协程 。
3.2 处处都要使用非阻塞代码写协程就意味着你要一值写一些非阻塞的代码,使用各种异步版本的库,比如后面的异步爬虫教程中用的 aiohttp 就是一个异步版本的request库等 。不过这些缺点并不能影响到使用协程的优势 。
4. 协程与异步上面想必你已经完全掌握了,接下来,我们用睡眠来模仿一下耗时的 IO 操作 。
Python协程还不理解?请收下这份超详细的异步编程教程

文章插图
 
输出结果:
Python协程还不理解?请收下这份超详细的异步编程教程

文章插图
 
tips:
注意区别 time.sleep() 这个是不能使用到异步里面的 sleep,如果你直接用 time 模块里面的 说了 sleep 那代码是真正睡眠了,不会执行其他任务了 。所以需要使用 asyncio.sleep() 的睡眠才可以 。requests 包也是同理,所以接下来我会给大家讲解一个新的包(aiohttp),我们将用 aiohttp 来代替 requests 。
接下来我们来分析一下输出结果:
Python协程还不理解?请收下这份超详细的异步编程教程

文章插图
 
这时候细心的小伙伴有可能会说,我们添加任务进去的时候是 0、1、2、3,可是在执行的时候却是 3、1、0、2这就是我上面说的异步是不可控,随机的 。
小结:
我在使用异步的时候,上面一共说到了三种:
执行单个任务:
  1. await 执行异步
  2. asyncio.create_task(function)
执行多个任务:
  1. 获取事件循环:loop = asyncio.get_event_loop()、loop.run_until_complete(asyncio.wait(list))
5. 异步爬虫实战
Python协程还不理解?请收下这份超详细的异步编程教程

文章插图
 
抓取目标网站:百思不得姐
Python协程还不理解?请收下这份超详细的异步编程教程

文章插图
 
输出结果:
Python协程还不理解?请收下这份超详细的异步编程教程


推荐阅读