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中Django框架利用url来控制登录的方法
Jul 25 Python
python3设计模式之简单工厂模式
Oct 17 Python
python 剪切移动文件的实现代码
Aug 02 Python
Python XlsxWriter模块Chart类用法实例分析
Mar 11 Python
Python3日期与时间戳转换的几种方法详解
Jun 04 Python
python 实现将文件或文件夹用相对路径打包为 tar.gz 文件的方法
Jun 10 Python
python多进程(加入进程池)操作常见案例
Oct 21 Python
Python3查找列表中重复元素的个数的3种方法详解
Feb 13 Python
ubuntu16.04升级Python3.5到Python3.7的方法步骤
Aug 20 Python
Python计算矩阵的和积的实例详解
Sep 10 Python
python批量检查两个对应的txt文件的行数是否一致的实例代码
Oct 31 Python
Python爬虫入门案例之回车桌面壁纸网美女图片采集
Oct 16 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 fsockopen写的HTTP下载的类
2007/02/22 PHP
php实现将任意进制数转换成10进制的方法
2015/04/17 PHP
tp5(thinkPHP5框架)captcha验证码配置及验证操作示例
2019/05/28 PHP
PHP实现的文件浏览器功能简单示例
2019/09/12 PHP
静态页面的值传递(三部曲)
2006/09/25 Javascript
按钮JS复制文本框和表格的代码
2011/04/01 Javascript
JS随机漂浮广告代码具体实例
2013/11/19 Javascript
javascript中不等于的代码是什么怎么写
2013/12/29 Javascript
使用正则表达式的格式化与高亮显示json字符串
2014/12/03 Javascript
简介JavaScript中Math.LOG10E属性的使用
2015/06/14 Javascript
浅谈JavaScript字符串拼接
2015/06/25 Javascript
浅谈javascript中的DOM方法
2015/07/16 Javascript
jQuery-1.9.1源码分析系列(十)事件系统之事件包装
2015/11/20 Javascript
jquery获取table指定行和列的数据方法(当前选中行、列)
2016/11/07 Javascript
JS 调试中常见的报错问题解决方法
2017/05/20 Javascript
微信小程序 POST请求的实例详解
2017/09/29 Javascript
js实现HTML中Select二级联动的实例
2018/01/05 Javascript
Vue.js进阶知识点总结
2018/04/01 Javascript
NodeJS和浏览器中this关键字的不同之处
2021/03/03 NodeJs
详解Python操作RabbitMQ服务器消息队列的远程结果返回
2016/06/30 Python
Python基于pygame模块播放MP3的方法示例
2017/09/30 Python
matplotlib savefig 保存图片大小的实例
2018/05/24 Python
pycharm在调试python时执行其他语句的方法
2018/11/29 Python
Python3爬虫爬取英雄联盟高清桌面壁纸功能示例【基于Scrapy框架】
2018/12/05 Python
CSS3 简写animation
2012/05/10 HTML / CSS
世界上最大的乐器零售商:Guitar Center
2017/11/07 全球购物
党员批评与自我批评
2014/02/12 职场文书
财务助理岗位职责范本
2014/10/09 职场文书
小学教师学习党的群众路线教育实践活动心得体会
2014/10/31 职场文书
自查自纠整改报告
2014/11/06 职场文书
2015年元旦联欢晚会活动总结
2014/11/28 职场文书
2014年销售员工作总结
2014/12/01 职场文书
北大自主招生自荐信
2015/03/04 职场文书
实习指导老师意见
2015/06/04 职场文书
golang 如何用反射reflect操作结构体
2021/04/28 Golang
webpack的移动端适配方案小结
2021/07/25 Javascript