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 Queue模块详解
Nov 30 Python
Python进程通信之匿名管道实例讲解
Apr 11 Python
python3.6连接MySQL和表的创建与删除实例代码
Dec 28 Python
Python批量提取PDF文件中文本的脚本
Mar 14 Python
Python反爬虫技术之防止IP地址被封杀的讲解
Jan 09 Python
python 控制Asterisk AMI接口外呼电话的例子
Aug 08 Python
python 使用pygame工具包实现贪吃蛇游戏(多彩版)
Oct 30 Python
Python实现井字棋小游戏
Mar 09 Python
Python HTMLTestRunner库安装过程解析
May 25 Python
Python 字符串池化的前提
Jul 03 Python
Python如何将模块打包并发布
Aug 30 Python
PyQt实现计数器的方法示例
Jan 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代码书写习惯优化小结
2013/06/20 PHP
PHP中使用循环实现的金字塔图形
2014/11/08 PHP
浅析Yii2缓存的使用
2016/05/10 PHP
PHP+百度AI OCR文字识别实现了图片的文字识别功能
2019/05/08 PHP
PHP创建XML的方法示例【基于DOMDocument类及SimpleXMLElement类】
2019/09/10 PHP
jquery 图片轮换效果
2010/07/29 Javascript
js的匿名函数使用介绍
2013/12/11 Javascript
禁止IE用右键的JS代码
2013/12/30 Javascript
JavaScript中的分号插入机制详细介绍
2015/02/11 Javascript
jQuery简单几行代码实现tab切换
2015/03/10 Javascript
在easyUI开发中,出现jquery.easyui.min.js函数库问题的解决办法
2015/09/11 Javascript
JavaScript 对象字面量讲解
2016/06/06 Javascript
Javascript中call,apply,bind方法的详解与总结
2016/12/12 Javascript
angularJS 指令封装回到顶部示例详解
2017/01/22 Javascript
浅谈原生JS实现jQuery的animate()动画示例
2017/03/08 Javascript
关于vue中watch检测到不到对象属性的变化的解决方法
2018/02/08 Javascript
layui数据表格 table.render 报错的解决方法
2019/09/29 Javascript
Vue实现腾讯云点播视频上传功能的实现代码
2020/08/17 Javascript
Python的Django框架中消息通知的计数器实现教程
2016/06/13 Python
浅谈python抛出异常、自定义异常, 传递异常
2016/06/20 Python
pycharm的console输入实现换行的方法
2019/01/16 Python
python字符串替换re.sub()方法解析
2019/09/18 Python
python tkinter之 复选、文本、下拉的实现
2020/03/04 Python
使用canvas压缩图片大小的方法示例
2019/08/02 HTML / CSS
美国医生配方营养补充剂供应商:Healthy Directions
2019/07/10 全球购物
致400米运动员广播稿
2014/02/07 职场文书
运动会获奖感言
2014/02/11 职场文书
学习十八大报告感言
2014/02/28 职场文书
2014年五一劳动节社区活动总结
2014/04/14 职场文书
单位授权委托书范文
2014/08/02 职场文书
2014旅游局领导班子四风问题对照检查材料思想汇报
2014/09/19 职场文书
钱塘江大潮导游词
2015/02/03 职场文书
综合实践活动报告
2015/02/05 职场文书
2015教师年度考核评语
2015/03/25 职场文书
刑事上诉状范文
2015/05/22 职场文书
Django路由层如何获取正确的url
2021/07/15 Python