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 相关文章推荐
py中的目录与文件判别代码
Jul 16 Python
跟老齐学Python之赋值,简单也不简单
Sep 24 Python
Python 爬虫之超链接 url中含有中文出错及解决办法
Aug 03 Python
python中map的基本用法示例
Sep 10 Python
用Python实现校园通知更新提醒功能
Nov 23 Python
tensorboard 可以显示graph,却不能显示scalar的解决方式
Feb 15 Python
Python对wav文件的重采样实例
Feb 25 Python
Pytorch对Himmelblau函数的优化详解
Feb 29 Python
python 获取当前目录下的文件目录和文件名实例代码详解
Mar 10 Python
如何理解Python中包的引入
May 29 Python
Python数据分析入门之教你怎么搭建环境
May 13 Python
Python一些基本的图像操作和处理总结
Jun 23 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/08/18 PHP
用php实现的下载css文件中的图片的代码
2010/02/08 PHP
php中++i 与 i++ 的区别
2012/08/08 PHP
php文件管理基本功能简单操作
2017/01/16 PHP
修改jquery里的dialog对话框插件为框架页(iframe) 的方法
2010/09/14 Javascript
一些常用的JavaScript函数(json)附详细说明
2011/05/25 Javascript
使用jQuery操作Cookies的实现代码
2011/10/09 Javascript
Three.js源码阅读笔记(光照部分)
2012/12/27 Javascript
Jquery显示和隐藏元素或设为只读(含Ligerui的控件禁用,实例说明介绍)
2013/07/09 Javascript
Javascript实现滚动图片新闻的实例代码
2013/11/27 Javascript
jquery简单的弹出层浮动层代码
2015/04/27 Javascript
javascript遇到html5的一些表单属性
2015/07/05 Javascript
jQuery插件实现静态HTML验证码校验
2015/11/06 Javascript
解决WordPress使用CDN后博文无法评论的错误
2015/12/15 Javascript
ES6新特性之解构、参数、模块和记号用法示例
2017/04/01 Javascript
AngularJS的脏检查深入分析
2017/04/22 Javascript
mui开发中获取单选按钮、复选框的值(实例讲解)
2017/07/24 Javascript
分享ES6的7个实用技巧
2018/01/18 Javascript
浅谈Webpack打包优化技巧
2018/06/12 Javascript
使用NestJS开发Node.js应用的方法
2018/12/03 Javascript
解决Layui当中的导航条动态添加后渲染失败的问题
2019/09/25 Javascript
[00:56]PWL开团时刻DAY8——追追追追追!
2020/11/09 DOTA
python统计文本字符串里单词出现频率的方法
2015/05/26 Python
Python实现语音识别和语音合成功能
2019/09/20 Python
Tensorflow的常用矩阵生成方式
2020/01/04 Python
pyecharts绘制中国2020肺炎疫情地图的实例代码
2020/02/12 Python
Python+OpenCV图像处理—— 色彩空间转换
2020/10/22 Python
GitHub上值得推荐的8个python 项目
2020/10/30 Python
美国求婚钻戒网站:Super Jeweler
2016/08/27 全球购物
大学生预备党员自我评价分享
2013/11/16 职场文书
2014年最新学习全国两会精神心得
2014/03/17 职场文书
数学教师个人总结
2015/02/06 职场文书
学习保证书100字
2015/02/26 职场文书
2017大学生寒假社会实践心得体会
2016/01/14 职场文书
电工生产实习心得体会
2016/01/22 职场文书
2019班干部竞选演讲稿范本!
2019/07/08 职场文书