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中method的参数传递过程
Apr 02 Python
pygame学习笔记(2):画点的三种方法和动画实例
Apr 15 Python
python MySQLdb Windows下安装教程及问题解决方法
May 09 Python
Python编程实现粒子群算法(PSO)详解
Nov 13 Python
Django的HttpRequest和HttpResponse对象详解
Jan 26 Python
解决python升级引起的pip执行错误的问题
Jun 12 Python
python实现将汉字保存成文本的方法
Nov 16 Python
Python 如何优雅的将数字转化为时间格式的方法
Sep 26 Python
Python 异常处理Ⅳ过程图解
Oct 18 Python
python在不同条件下的输入与输出
Feb 13 Python
django 外键创建注意事项说明
May 20 Python
python tkinter模块的简单使用
Apr 07 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设计模式 Mediator (中介者模式)
2011/06/26 PHP
Ping服务的php实现方法,让网站快速被收录
2012/02/04 PHP
php实现俄罗斯乘法实例
2015/03/07 PHP
PHP验证码无法显示的原因及解决办法
2017/08/11 PHP
详细介绍8款超实用JavaScript框架
2013/10/25 Javascript
jquery 缓存问题的几个解决方法
2013/11/11 Javascript
JavaScript中操作字符串小结
2015/05/04 Javascript
使用impress.js制作幻灯片
2015/09/09 Javascript
js实现文字垂直滚动和鼠标悬停效果
2015/12/31 Javascript
JavaScript动态检验密码强度的实现方法
2016/11/09 Javascript
Bootstrap 3浏览器兼容性问题及解决方案
2017/04/11 Javascript
vue+egg+jwt实现登录验证的示例代码
2019/05/18 Javascript
vue中实现回车键登录功能
2020/02/19 Javascript
vue的webcamjs集成方式
2020/11/16 Javascript
如何在JavaScript中使用localStorage详情
2021/02/04 Javascript
[02:43]DOTA2英雄基础教程 半人马战行者
2014/01/13 DOTA
Python简单获取网卡名称及其IP地址的方法【基于psutil模块】
2018/05/24 Python
Python读取txt内容写入xls格式excel中的方法
2018/10/11 Python
pandas 条件搜索返回列表的方法
2018/10/30 Python
Python骚操作之动态定义函数
2019/03/26 Python
如何使用django的MTV开发模式返回一个网页
2019/07/22 Python
pytorch自定义初始化权重的方法
2019/08/17 Python
Python使用__new__()方法为对象分配内存及返回对象的引用示例
2019/09/20 Python
python Gabor滤波器讲解
2020/10/26 Python
Selenium获取登录Cookies并添加Cookies自动登录的方法
2020/12/04 Python
沙特阿拉伯网上购物:Sayidaty Mall
2018/05/06 全球购物
线程的基本概念、线程的基本状态以及状态之间的关系
2012/10/26 面试题
大学生最常用的自我评价
2013/12/07 职场文书
写给女生的道歉信
2014/01/08 职场文书
民间借贷借条范本
2015/05/25 职场文书
在校生证明
2015/06/17 职场文书
2015国庆节66周年标语
2015/07/30 职场文书
学校教代会开幕词
2016/03/04 职场文书
go:垃圾回收GC触发条件详解
2021/04/24 Golang
Python Django ORM连表正反操作技巧
2021/06/13 Python
APP界面设计技巧和注意事项
2022/04/29 杂记