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对象体系深入分析
Oct 28 Python
Python封装shell命令实例分析
May 05 Python
Python实现的异步代理爬虫及代理池
Mar 17 Python
Python OpenCV实现图片上输出中文
Jan 22 Python
用scikit-learn和pandas学习线性回归的方法
Jun 21 Python
opencv3/python 鼠标响应操作详解
Dec 11 Python
pytorch实现mnist数据集的图像可视化及保存
Jan 14 Python
PHP基于phpqrcode类库生成二维码过程解析
May 28 Python
Python 如何在字符串中插入变量
Aug 01 Python
怎么解决pycharm license Acti的方法
Oct 28 Python
Python实现王者荣耀自动刷金币的完整步骤
Jan 22 Python
python 合并多个excel中同名的sheet
Jan 22 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
ThinkPHP项目分组配置方法分析
2016/03/23 PHP
ThinkPHP静态缓存简单配置和使用方法详解
2016/03/23 PHP
yii2分页之实现跳转到具体某页的实例代码
2016/06/02 PHP
Yii遍历行下每列数据的方法
2016/10/17 PHP
PHP简单实现二维数组的矩阵转置操作示例
2017/11/24 PHP
Json对象替换字符串占位符实现代码
2010/11/17 Javascript
js判断生效时间不得大于失效时间的思路及代码
2013/04/23 Javascript
javascript实现input file上传图片预览效果
2015/12/31 Javascript
漫谈JS引擎的运行机制 你应该知道什么
2016/06/15 Javascript
概述一个页面从输入URL到页面加载完的过程
2016/12/16 Javascript
jQuery插件echarts实现的多折线图效果示例【附demo源码下载】
2017/03/04 Javascript
使用Math.max,Math.min获取数组中的最值实例
2017/04/25 Javascript
JavaScript求一个数组中重复出现次数最多的元素及其下标位置示例
2018/07/23 Javascript
vue表单验证你真的会了吗?vue表单验证(form)validate
2019/04/07 Javascript
JavaScript 严格模式(use strict)用法实例分析
2020/03/04 Javascript
JS面向对象实现飞机大战
2020/08/26 Javascript
jQuery实现日历效果
2020/09/11 jQuery
[05:31]DOTA2英雄梦之声_第04期_光之守卫
2014/06/23 DOTA
使用Python编写简单网络爬虫抓取视频下载资源
2014/11/04 Python
Python的迭代器和生成器使用实例
2015/01/14 Python
Python可跨平台实现获取按键的方法
2015/03/05 Python
Python制作豆瓣图片的爬虫
2017/12/28 Python
python从子线程中获得返回值的方法
2019/01/30 Python
在python中使用pymysql往mysql数据库中插入(insert)数据实例
2020/03/02 Python
python读取xml文件方法解析
2020/08/04 Python
比较基础的php面试题及答案-填空题
2014/04/26 面试题
系统管理员的职责包括那些?管理的对象是什么?
2016/09/20 面试题
Java Servlet API中forward() 与redirect()的区别
2014/04/20 面试题
工伤死亡理赔协议书
2014/10/20 职场文书
大二学生自我检讨书
2014/10/23 职场文书
个人事迹材料怎么写
2014/12/30 职场文书
2015年学校禁毒工作总结
2015/05/27 职场文书
教你利用python实现企业微信发送消息
2021/05/23 Python
springboot利用redis、Redisson处理并发问题的操作
2021/06/18 Java/Android
详解Python中的进程和线程
2021/06/23 Python
Python常用配置文件ini、json、yaml读写总结
2021/07/09 Python