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基于右递归解决八皇后问题的方法
May 25 Python
Django验证码的生成与使用示例
May 20 Python
python构建自定义回调函数详解
Jun 20 Python
Python3之文件读写操作的实例讲解
Jan 23 Python
pip指定python位置安装软件包的方法
Jul 12 Python
Python Django 添加首页尾页上一页下一页代码实例
Aug 21 Python
pytorch标签转onehot形式实例
Jan 02 Python
python爬虫爬取监控教务系统的思路详解
Jan 08 Python
基于python3生成标签云代码解析
Feb 18 Python
python中threading开启关闭线程操作
May 02 Python
如何使用python-opencv批量生成带噪点噪线的数字验证码
Dec 21 Python
Python 多线程处理任务实例
Nov 07 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获取当月最后一天函数分享
2015/02/02 PHP
修改yii2.0用户登录使用的user表为其它的表实现方法(推荐)
2017/08/01 PHP
php检查函数必传参数是否存在的实例详解
2017/08/28 PHP
kindeditor 加入七牛云上传的实例讲解
2017/11/12 PHP
JavaScript去掉空格的方法集合
2010/12/28 Javascript
提高NodeJS中SSL服务的性能
2014/07/15 NodeJs
Jquery修改页面标题title其它JS失效的解决方法
2014/10/31 Javascript
ECMA5数组的新增方法有哪些及forEach()模仿实现
2015/11/03 Javascript
基于Bootstrap的Metronic框架实现条码和二维码的生成及打印处理操作
2016/08/29 Javascript
jQuery实现的自定义滚动条实例详解
2016/09/20 Javascript
bootstrap多种样式进度条展示
2016/12/20 Javascript
解决JS内存泄露之js对象和dom对象互相引用问题
2017/06/25 Javascript
vue-router+vuex addRoutes实现路由动态加载及菜单动态加载
2017/09/28 Javascript
实现单层json按照key字母顺序排序的示例
2017/12/06 Javascript
Vue集成Iframe页面的方法示例
2017/12/12 Javascript
element-ui带输入建议的input框踩坑(输入建议空白以及会闪出上一次的输入建议问题)
2019/01/15 Javascript
图解javascript作用域链
2019/05/27 Javascript
Layui带搜索的下拉框的使用以及动态数据绑定方法
2019/09/28 Javascript
React生命周期原理与用法踩坑笔记
2020/04/28 Javascript
vue 实现setInterval 创建和销毁实例
2020/07/21 Javascript
[00:20]TI9不朽观赛名额抽取
2019/08/05 DOTA
Python遍历numpy数组的实例
2018/04/04 Python
python自动重试第三方包retrying模块的方法
2018/04/24 Python
树莓派4B+opencv4+python 打开摄像头的实现方法
2019/10/18 Python
用Python画小女孩放风筝的示例
2019/11/23 Python
Python Tornado核心及相关原理详解
2020/06/24 Python
alice McCALL官网:澳大利亚时尚品牌
2020/11/16 全球购物
药剂学专业应届生自荐信
2013/09/29 职场文书
电气专业应届生求职信
2013/11/01 职场文书
简历自我评价怎么写好呢?
2014/01/04 职场文书
怎么写自荐书范文
2014/02/12 职场文书
小学秋季运动会报道稿
2014/09/30 职场文书
2014年客房部工作总结
2014/11/22 职场文书
长征观后感
2015/06/09 职场文书
2020优秀员工演讲稿(三篇)
2019/10/17 职场文书
启迪人心的励志语录:脾气永远不要大于本事
2020/01/02 职场文书