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升级提示Tkinter模块找不到的解决方法
Aug 22 Python
详解Python中break语句的用法
May 14 Python
Python实现基于多线程、多用户的FTP服务器与客户端功能完整实例
Aug 18 Python
TF-IDF与余弦相似性的应用(一) 自动提取关键词
Dec 21 Python
Python图形绘制操作之正弦曲线实现方法分析
Dec 25 Python
Python爬虫框架Scrapy实例代码
Mar 04 Python
Python计算一个给定时间点前一个月和后一个月第一天的方法
May 29 Python
python3写的简单本地文件上传服务器实例
Jun 04 Python
numpy中矩阵合并的实例
Jun 15 Python
Python魔法方法 容器部方法详解
Jan 02 Python
django实现模型字段动态choice的操作
Apr 01 Python
python录音并调用百度语音识别接口的示例
Dec 01 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
Breeze 文章管理系统 v1.0.0正式发布
2006/12/14 PHP
PHP数组的交集array_intersect(),array_intersect_assoc(),array_inter_key()函数的小问题
2011/05/29 PHP
php 无法加载mysql的module的时候的配置的解决方案引发的思考
2012/01/27 PHP
使用php从身份证号中获取一系列线索(星座、生肖、生日等)
2016/05/11 PHP
php使用str_shuffle()函数生成随机字符串的方法分析
2017/02/17 PHP
php常用的工具开发整理
2019/09/26 PHP
在JavaScript中遭遇级联表达式陷阱
2007/03/08 Javascript
理解Javascript_15_作用域分配与变量访问规则,再送个闭包
2010/10/20 Javascript
JavaScript中的apply()方法和call()方法使用介绍
2012/07/25 Javascript
JavaScript 参数中的数组展开 [译]
2012/09/21 Javascript
node.js中的fs.lchmodSync方法使用说明
2014/12/16 Javascript
DOM节点深度克隆函数cloneNode()用法实例
2015/01/12 Javascript
JavaScript截取、切割字符串的技巧
2016/01/07 Javascript
JavaScript中的闭包
2016/02/24 Javascript
js前端导出Excel的方法
2017/11/01 Javascript
ajax前台后台跨域请求处理方式
2018/02/08 Javascript
微信小程序实现手指触摸画板
2018/07/09 Javascript
微信JS-SDK实现微信会员卡功能(给用户微信卡包里发送会员卡)
2019/07/25 Javascript
vue开发拖拽进度条滑动组件
2019/09/21 Javascript
js对象简介与基本用法示例
2020/03/13 Javascript
vue 解决兄弟组件、跨组件深层次的通信操作
2020/07/27 Javascript
Django实现发送邮件找回密码功能
2019/08/12 Python
Python Numpy数组扩展repeat和tile使用实例解析
2019/12/09 Python
美国高档帽子网上商店:Hats.com
2018/08/09 全球购物
送给他或她的礼物:FUN.com
2018/08/17 全球购物
会计毕业生求职简历的自我评价
2013/10/20 职场文书
工作自我评价怎么写
2014/01/29 职场文书
群众路线专项整治方案
2014/10/27 职场文书
教师党员自我评价2015
2015/03/04 职场文书
酒店工程部主管岗位职责
2015/04/16 职场文书
大学生逃课检讨书
2015/05/04 职场文书
2016年国庆节假期旅游工作总结
2016/04/01 职场文书
详解MySQL数据库千万级数据查询和存储
2021/05/18 MySQL
Python编程中Python与GIL互斥锁关系作用分析
2021/09/15 Python
python图像处理 PIL Image操作实例
2022/04/09 Python
Linux中文件的基本属性介绍
2022/06/01 Servers