Python中asyncio模块的深入讲解


Posted in Python onJune 10, 2019

1. 概述

Python中 asyncio 模块内置了对异步IO的支持,用于处理异步IO;是Python 3.4版本引入的标准库。

asyncio 的编程模型就是一个消息循环。我们从 asyncio 块中直接获取一个 EventLoop 的引用,然后把需要执行的协程扔到 EventLoop 中执行,就实现了异步IO。

2. 用asyncio实现Hello world

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time : 2019/1/9 11:23
# @Author : Arrow and Bullet
# @FileName: test.py
# @Software: PyCharm
# @Blog :https://blog.csdn.net/qq_41800366
import asyncio

@asyncio.coroutine
def hello():
 print("Hello world!")
 # 异步调用asyncio.sleep(2): 
 yield from asyncio.sleep(2)
 print("Hello again!")

# 获取EventLoop:
loop = asyncio.get_event_loop()
# 执行coroutine
loop.run_until_complete(hello())
loop.close()

@asyncio.coroutine 把一个 generator 标记为 coroutine 类型,然后,我们就把这个 coroutine 扔到 EventLoop 中执行。

hello() 会首先打印出Hello world!,然后,yield from语法可以让我们方便地调用另一个generator。由于 asyncio.sleep() 也是一个 coroutine,所以线程不会等待 asyncio.sleep() ,而是直接中断并执行下一个消息循环。当asyncio.sleep()返回时,线程就可以从yield from拿到返回值(此处是None),然后接着执行下一行语句。

把asyncio.sleep(2)看成是一个耗时2秒的IO操作(比如读取大文件),在此期间,主线程并未等待,而是去执行 EventLoop 中其他可以执行的 coroutine 了,因此可以实现并发执行。

我们用task封装两个coroutine试试:

import threading
import asyncio


@asyncio.coroutine
def hello():
 print('Hello world! (%s)' % threading.currentThread())
 yield from asyncio.sleep(2)
 print('Hello again! (%s)' % threading.currentThread())


loop = asyncio.get_event_loop()
tasks = [hello(), hello()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

观察执行过程:

Hello world! (<_MainThread(MainThread, started 140735195337472)>)
Hello world! (<_MainThread(MainThread, started 140735195337472)>)
(暂停约2秒)
Hello again! (<_MainThread(MainThread, started 140735195337472)>)
Hello again! (<_MainThread(MainThread, started 140735195337472)>)

由打印的当前线程名称可以看出,两个 coroutine 是由同一个线程并发执行的。

如果把 asyncio.sleep() 换成真正的IO操作,则多个 coroutine 就可以由一个线程并发执行。

我们用asyncio的异步网络连接来获取sina、sohu和163的网站首页:

import asyncio


@asyncio.coroutine
def wget(host):
 print('wget %s...' % host)
 connect = asyncio.open_connection(host, 80) # 创建连接
 reader, writer = yield from connect
 header = 'GET / HTTP/1.0\r\nHost: %s\r\n\r\n' % host
 writer.write(header.encode('utf-8'))
 yield from writer.drain()
 while True:
  line = yield from reader.readline()
  if line == b'\r\n':
   break
  print('%s header > %s' % (host, line.decode('utf-8').rstrip()))
 # Ignore the body, close the socket
 writer.close()


loop = asyncio.get_event_loop()
tasks = [wget(host) for host in ['www.sina.com.cn', 'www.sohu.com', 'www.163.com']]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

执行结果如下:

wget www.sohu.com...
wget www.sina.com.cn...
wget www.163.com...
(等待一段时间)
(打印出sohu的header)
www.sohu.com header > HTTP/1.1 200 OK
www.sohu.com header > Content-Type: text/html
...
(打印出sina的header)
www.sina.com.cn header > HTTP/1.1 200 OK
www.sina.com.cn header > Date: Wed, 20 May 2015 04:56:33 GMT
...
(打印出163的header)
www.163.com header > HTTP/1.0 302 Moved Temporarily
www.163.com header > Server: Cdn Cache Server V2.0
...

可见3个连接由一个线程通过coroutine并发完成。

3. 小结

asyncio提供了完善的异步IO支持;

异步操作需要在coroutine中通过yield from完成;

多个coroutine可以封装成一组Task然后并发执行。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
在Python中操作时间之tzset()方法的使用教程
May 22 Python
python自动翻译实现方法
May 28 Python
Python 提取dict转换为xml/json/table并输出的实现代码
Aug 28 Python
Python自动化运维之IP地址处理模块详解
Dec 10 Python
解决pycharm运行出错,代码正确结果不显示的问题
Nov 30 Python
使用python代码进行身份证号校验的实现示例
Nov 21 Python
基于Python3.6中的OpenCV实现图片色彩空间的转换
Feb 03 Python
python实现文字版扫雷
Apr 24 Python
pycharm远程连接vagrant虚拟机中mariadb数据库
Jun 05 Python
Python3爬虫关于识别点触点选验证码的实例讲解
Jul 30 Python
Python Pandas数据分析工具用法实例
Nov 05 Python
Python实现智慧校园自动评教全新版
Jun 18 Python
Python中的asyncio代码详解
Jun 10 #Python
Django集成CAS单点登录的方法示例
Jun 10 #Python
详解Python中的测试工具
Jun 09 #Python
Python中函数参数匹配模型详解
Jun 09 #Python
Python程序包的构建和发布过程示例详解
Jun 09 #Python
Python面向对象之继承和多态用法分析
Jun 08 #Python
Python基本数据结构之字典类型dict用法分析
Jun 08 #Python
You might like
PHP实时显示输出
2008/10/02 PHP
PHP 文章中的远程图片采集到本地的代码
2009/07/30 PHP
PHP初学者常见问题集合 修正版(21问答)
2010/03/23 PHP
PHP中redis的用法深入解析
2014/02/20 PHP
PHP实现AES256加密算法实例
2014/09/22 PHP
php eval函数一句话木马代码
2015/05/21 PHP
PHP6新特性分析
2016/03/03 PHP
javascript使用activex控件的代码
2011/01/27 Javascript
windows8.1+iis8.5下安装node.js开发环境
2014/12/12 Javascript
jQuery+html5+css3实现圆角无刷新表单带输入验证功能代码
2015/08/21 Javascript
Bootstrap popover 实现鼠标移入移除显示隐藏功能方法
2018/01/24 Javascript
解决vue this.$forceUpdate() 处理页面刷新问题(v-for循环值刷新等)
2018/07/26 Javascript
9102了,你还不会移动端真机调试吗
2019/03/25 Javascript
Vue之beforeEach非登录不能访问的实现(代码亲测)
2019/07/18 Javascript
python执行外部程序的常用方法小结
2015/03/21 Python
Python实现合并两个列表的方法分析
2018/05/28 Python
selenium在执行phantomjs的API并获取执行结果的方法
2018/12/17 Python
python2 中 unicode 和 str 之间的转换及与python3 str 的区别
2019/07/25 Python
python 插入日期数据到Oracle实例
2020/03/02 Python
pandas DataFrame 数据选取,修改,切片的实现
2020/04/24 Python
python 图像判断,清晰度(明暗),彩色与黑白实例
2020/06/04 Python
PyCharm 2020.1版安装破解注册码永久激活(激活到2089年)
2020/09/24 Python
python中字典增加和删除使用方法
2020/09/30 Python
解析HTML5中的新功能本地存储localStorage
2016/03/01 HTML / CSS
使用html5 canvas绘制圆环动效
2019/06/03 HTML / CSS
C语言基础笔试题
2013/04/27 面试题
计算机应用专业毕业生求职信
2013/10/24 职场文书
初入社会应届生求职信
2013/11/18 职场文书
安全资料员岗位职责
2013/12/14 职场文书
班组建设经验交流材料
2014/05/12 职场文书
个人总结与自我评价
2014/09/18 职场文书
个人自荐书范文
2015/03/09 职场文书
SQL SERVER实现连接与合并查询
2022/02/24 SQL Server
TypeScript 使用 Tuple Union 声明函数重载
2022/04/07 Javascript
微信告警的zabbix监控系统 监控整个NGINX集群
2022/04/18 Servers
Windows server 2012 R2 安装IIS服务器
2022/04/29 Servers