因为要找工作,把之前自己搞的爬虫整理一下,没有项目经验真蛋疼,只能做这种水的不行的东西。。。T  T,希望找工作能有好结果。

之前爬虫使用的是requests+多线程/多进程,后来随着前几天的深入了解,才发现,对于爬虫来说,真正的瓶颈并不是CPU的处理速度,而是对于网页抓取时候的往返时间,因为如果采用requests+多线程/多进程,他本身是阻塞式的编程,所以时间都花费在了等待网页结果的返回和对爬取到的数据的写入上面。而如果采用非阻塞编程,那么就没有这个困扰。这边首先要理解一下阻塞和非阻塞的区别

1.阻塞调用是指调用结果返回之前,当前线程会被挂起(线程进入非可执行状态,在这个状态下,CPU不会给线程分配时间片,即线程暂停运行)。函数只有在得到结果之后才会返回。

2.对于非阻塞则不会挂起,直接执行接下去的程序,返回结果后再回来处理返回值。

python 3.4开始就支持异步IO编程,提供了asyncio库,但是3.4中采用的是@asyncio.coroutine和yield from这和原来的generator关键字yield不好区分,在3.5中,采用了async(表示携程)和await关键字,这样就好区分多了。

写这篇博客的目的在于,网上看了一堆资料,自己还是没有理解如何进行asyncio的编程,用到自己代码里时候,还是有各种错误,因此打算看一下asyncio的官方手册并好好梳理一下,希望时间的来的及~

https://docs.python.org/3/library/asyncio.html

这边用一个简单的官方例子来说明async和await的执行顺序。

import asyncioasync def compute(x, y):print("Compute %s + %s ..." % (x, y))await asyncio.sleep(1.0)return x + yasync def print_sum(x, y):result = await compute(x, y)print("%s + %s = %s" % (x, y, result))loop = asyncio.get_event_loop()
loop.run_until_complete(print_sum(1, 2))
loop.close()

如果不使用async和await,这个程序的运行顺序也很好理解

1.print_sum(1,2)将参数1,2传递给函数print_sum

2.先执行第一句,result = compute(x,y),

3.将1,2传递给compute函数,compute函数收到参数

4.先执行 print("Compute %s + %s ..." % (x, y))打印出Compute 1 + 2 ...

5.执行sleep(1.0)程序挂起一秒

6.返回1+2的值3

7.print_sum的result收到返回值3,执行print("%s + %s = %s" % (x, y, result)),打印出1 + 2 = 3

8.程序结束

如果采用异步的话,他执行顺序是怎么样的呢?

下图是他官方文档的说明:

要理解上图,首先我们要理解Event_loop,feture,task等概念,详细的可以参考官方文档或者http://my.oschina.net/lionets/blog/499803

首先get_event_loop()方法让我们得到一个消息环,event loop对象包括两部分:event和loop,event负责I/O时间通知二loop负责循环处理I/O通知并在就绪时调用回调。

event loop 内部维护着两个容器:_ready 和 _scheduled。类型分别是 deque 和 list。_ready 代表已经可以执行,_scheduled 代表计划执行。_scheduled 中的 handle 是可以 cancel 的。

要理解task,首先需要理解future对象(via http://my.oschina.net/lionets/blog/499803)

class asyncio.Future(*, loop=None) 是对一个可调用对象的异步执行控制或者说代理的封装。因此具有如下方法:

  • cancel()
  • cancelled()
  • done()
  • result()
  • exception()
  • add_done_callback(fn)
  • remove_done_callback(fn)
  • set_result(result)
  • set_exception(exception)

注意 Future 并不包含可执行对象的本体,他只保存状态、结果、额外的回调函数这些东西。这也是上面称之为代理的原因。因为实际的调用过程是在 event loop 里发生的,event loop 负责在异步执行完成后向 future 对象写入 result 或 exception。这是异步任务的基本逻辑。

future 实例有三种状态:

  • PENDING
  • CANCELLED
  • FINISHED

初始状态为 PENDING,当调用 cancel() 方法时会立即进入 CANCELLED 状态并 schedule callbacks。当被调用 set_result()时会进入 FINISHED 状态,并 schedule callbacks。当然两种情况下传入 callback 的参数会不同。

Task是 Future 的子类。因为 Future 没有保存其相关可执行对象的信息,我们 schedule the execution of a coroutine 这件事一般是通过 Task 对象来做的。 Task 提供了一种机制用于当 future 完成时唤醒父级协程。即为当 await future 时,task 对象会将此 future 保存到 _fut_waiter 对象中,并为其添加一个名为_wake_up() 的回调。

继续分析上面这段代码,首先async def创建一个coroutine object,get_event_loop创建一个消息环,接下去,run_until_complete()接受coroutine object对象,通过隐式转换(ensure_future())将其包装成一个future,这边是一个task对象(内部实现机制我其实也并不是非常确定,大致是这样,比如如何从future转换成task??)

1.get_event_loop()创建消息环

2.print_sum返回一个携程对象(coroutine object)

3.print_sum(1,2)接受参数

4.result = await compute(x,y),此时程序挂起,直接调用compute(1,2)

5.打印出Compute 1 + 2 ...

6.执行sleep(1.0) 由于使用await,所以sleep(1.0)被挂起,直接执行下一句

7.这边由于只有一个task,即print_sum(1,2),因此没有其他task可以执行,所以result等待compute(x,y)的返回值,等待1秒以后,返回1+2的值3

然后执行print("%s + %s = %s" % (x, y, result))

其实上面的程序可能还不能很明白async def和 await的调用过程到底是怎么样,稍微修改一下上面的程序就能更加明白他的执行过程了。

import asyncioasync def compute(x, y):print("Compute %s + %s ..." % (x, y))await asyncio.sleep(10.0)return x + yasync def print_sum(x, y):result = await compute(x, y)print("%s + %s = %s" % (x, y, result))loop = asyncio.get_event_loop()
tasks = [print_sum(1,2),print_sum(3,4)]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

把代码修改成这样,其他不变,多了一个task,为了更加直观,我把sleep(1.0)改成了sleep(10.0)

此时程序的执行结果是

Compute 3 + 4 ...
Compute 1 + 2 ...
暂停10秒左右
3 + 4 = 7
1 + 2 = 3

非常需要注意的就是这边暂停的时间,是10秒左右,不是20秒,所以他执行顺序是对于task

先执行print_sum(3,4)(这边tasks额执行顺序我不是非常理解,我多加了很多task测验,发现都是从第二个开始执行,然后最后执行第一个task,没懂是为什么)将3,4扔给compute,在compute中,sleep(10.0)挂起,此时不等待sleep(10.0)执行完毕,直接执行tasks中的另一个task,print_sum(1,2),将1,2扔给compute,在compute中,sleep(10.0)挂起,由于已经没有其他的task,所以等待第一个sleep(10.0)执行完毕以后返回3+4的结果为7,执行result = await compute(3, 4)后面的程序,即打印出3 + 4 = 7执行完毕以后,第二个sleep(10.0)也差不多返回了,因此回到原来挂起的result = await compute(1, 2),打印出1 + 2 = 3.所有task执行完毕,loop complete并且close。

这样整个async def 和await的执行流程就比较清楚了。

转载于:https://www.cnblogs.com/rockwall/p/5750900.html

Python asyncio库的学习和使用相关推荐

  1. Python第三方库pygame学习笔记(一)

    Pygame Python最经典的2D游戏开发第三方库,也支持3D游戏开发 Pygame适合用于游戏逻辑验证.游戏入门及系统演示验证 Pygame是一种游戏开发引擎,基本逻辑具有参考价值 pygame ...

  2. 《利用python进行数据分析》第二版 第13章-Python建模库介 学习笔记

    文章目录 一.pandas与建模代码结合 二.用patsy创建模型描述 Patsy公式中的数据转换 分类数据与Pastsy 三.statsmodels介绍 评估线性模型 评估时间序列处理 四.scik ...

  3. python的库怎么学习_怎样学习一个Python 库 ?

    什么是Python 库? python 自称是带电池的语言,在于其拥有大量的库,每个库都是某一行业比较顶尖的人才开发出来完成某一任务的代码集合.库提供一套解决方案,要用Python几乎离不开对几个库的 ...

  4. Python图像处理库PIL -- 学习资源

    Resources 官方指南PIL Handbook(建议看英文,翻译) pil下载 安装中文指南 from the PythonWare PIL home page 推荐先看Python Imagi ...

  5. 学python要考什么证-这十个Python常用库,学习Python的你必须要知道!

    ,包括原生库和第三方库.不过,有这么多Python库,有些库得不到应有的关注也就不足为奇了. 注意:很多人学Python过程中会遇到各种烦恼问题,没有人帮答疑.为此小编建了个Python全栈免费答疑交 ...

  6. python 没找到库_这十个Python常用库,学习Python的你必须要知道!

    包括原生库和第三方库.不过,有这么多Python库,有些库得不到应有的关注也就不足为奇了. 注意:很多人学Python过程中会遇到各种烦恼问题,没有人帮答疑.为此小编建了个Python全栈免费答疑交流 ...

  7. python常用的库有哪些餐厅_这十个Python常用库,学习Python的你必须要知道!

    想知道Python取得如此巨大成功的原因吗?只要看看Python提供的大量库就知道了 包括原生库和第三方库.不过,有这么多Python库,有些库得不到应有的关注也就不足为奇了.此外,只在一个领域里的工 ...

  8. Python机器学习库CatBoost学习使用

    最近,接触到一个比较新颖的Boost方法的机器学习库,觉得很有意思的,号称通用性很强,所以拿来上手试试,这里只是初步的学习使用,相关的参考链接放在下面. CatBoost是俄罗斯的搜索巨头Yandex ...

  9. Greenplum Python专用库gppylib学习——base.py

    base.py依赖的python包(Queue,threading,os,signal,subprocess/subprocess32,sys,time,warnings,paramiko,getpa ...

最新文章

  1. JNI错误记录--JNI程序调用本地库时JVM崩溃
  2. VISUAL STUDIO 2008 破解方法
  3. jQuery的next()、nextAll()、nextUntil()方法
  4. 使用C#为MSTest测试项目实现自定义断言
  5. 2017ACM/ICPC亚洲区沈阳站 C Hdu-6219 Empty Convex Polygons 计算几何 最大空凸包
  6. 消息推送生命周期_一套完整的APP推送体系方案|附思维导图
  7. 100万并发连接服务器笔记之Erlang完成1M并发连接目标
  8. MySQL数据库概述
  9. 人工智能(1)---从0开始搭建产品经理的AI认知体系
  10. 火星人敏捷开发手册2012-04-30新增敏捷日常跟进内容
  11. 复制不能复制的网页文字(实用篇) [图片]
  12. PHP error_log 新认知
  13. SpringBoot下Mybatis-注解动态sql开发的坑
  14. 前端json编辑器和富文本编辑器的使用
  15. 中国超市智能储物柜市场需求动态与盈利前景预测报告2022-2027年
  16. 针孔相机模型和相机内参矩阵K
  17. FC总线基础知识(2)——光纤交换机
  18. 印度萌新令人绝望的操作:提交PR“轰炸”近40万开发者,GitHub负责?
  19. ajax异步刷新gridview,如何刷新Gridview的内容(ajax)
  20. Cisco Firepower 1000 Series FTD Software 7.2.0 ASA Software 9.18.1

热门文章

  1. 一个具有20位地址和32位字长的存储器_详解西门子间接寻址之存储器间接寻址...
  2. 固件是通用的吗_冷镦和冷挤压是一回事吗,两者有什么区别?
  3. zabbix agent类型的所有key 值
  4. IE8 Beta2 已经放出来了
  5. 4、Cocos2dx 3.0游戏开发找小三之Hello World 分析
  6. linux基础命令-查看系统状态-free -m以及top命令详解
  7. [nRF51822] 5、 霸屏了——详解nRF51 SDK中的GPIOTE(从GPIO电平变化到产生中断事件的流程详解)...
  8. Ugly Number leetcode java
  9. 2015/10/19总结:ajax传参、jquery.validate自定义日期校验
  10. parseConf(配置文件解析器)