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中degrees()方法的使用
May 18 Python
Python实现多线程的两种方式分析
Aug 29 Python
小白入门篇使用Python搭建点击率预估模型
Oct 12 Python
python字典值排序并取出前n个key值的方法
Oct 17 Python
Python实现带下标索引的遍历操作示例
May 30 Python
PyCharm第一次安装及使用教程
Jan 08 Python
tensorflow之tf.record实现存浮点数数组
Feb 17 Python
python游戏开发的五个案例分享
Mar 09 Python
PYcharm 激活方法(推荐)
Mar 23 Python
python连接mysql数据库并读取数据的实现
Sep 25 Python
在 Python 中使用 7zip 备份文件的操作
Dec 11 Python
使用Selenium实现微博爬虫(预登录、展开全文、翻页)
Apr 13 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函数utf8转gb2312编码
2006/12/21 PHP
PHP函数学习之PHP函数点评
2012/07/05 PHP
php中读写文件与读写数据库的效率比较分享
2013/10/19 PHP
php实现删除指定目录下相关文件的方法
2014/10/20 PHP
php实现用手机关闭计算机(电脑)的方法
2015/04/22 PHP
PHP实现的json类实例
2015/07/28 PHP
php实现的debug log日志操作类实例
2016/07/12 PHP
Laravel使用scout集成elasticsearch做全文搜索的实现方法
2018/11/30 PHP
JS 文件传参及处理技巧分析
2010/05/13 Javascript
超越Jquery_01_isPlainObject分析与重构
2010/10/20 Javascript
JavaScript数据绑定实现一个简单的 MVVM 库
2016/04/08 Javascript
jQuery.Callbacks()回调函数队列用法详解
2016/06/14 Javascript
Javascript从数组中随机取出不同元素的两种方法
2016/09/22 Javascript
bootstrap使用validate实现简单校验功能
2016/12/02 Javascript
webpack独立打包和缓存处理详解
2017/04/03 Javascript
详解nodejs实现本地上传图片并预览功能(express4.0+)
2017/06/28 NodeJs
js Date()日期函数浏览器兼容问题解决方法
2017/09/12 Javascript
使用Electron构建React+Webpack桌面应用的方法
2017/12/15 Javascript
create-react-app安装出错问题解决方法
2018/09/04 Javascript
详解IOS微信上Vue单页面应用JSSDK签名失败解决方案
2018/11/14 Javascript
python+matplotlib绘制饼图散点图实例代码
2018/01/20 Python
Ubuntu下使用Python实现游戏制作中的切分图片功能
2018/03/30 Python
Python实现求一个集合所有子集的示例
2018/05/04 Python
python numpy格式化打印的实例
2018/05/14 Python
django_orm查询性能优化方法
2018/08/20 Python
解决python通过cx_Oracle模块连接Oracle乱码的问题
2018/10/18 Python
Python设计模式之模板方法模式实例详解
2019/01/17 Python
使用Python进行体育竞技分析(预测球队成绩)
2019/05/16 Python
python实现遍历文件夹图片并重命名
2020/03/23 Python
python如何判断IP地址合法性
2020/04/05 Python
意大利折扣和优惠券网站:Groupalia
2019/10/09 全球购物
德国2018年度最佳在线药房:Bodfeld Apotheke
2019/11/04 全球购物
C#实现对任一张表的数据进行增,删,改,查要求,运用Webservice,体现出三层架构
2014/07/11 面试题
语文教学感言
2014/02/06 职场文书
请假条怎么写
2014/04/10 职场文书
纯html+css实现奥运五环的示例代码
2021/08/02 HTML / CSS