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中的exec、eval使用实例
Sep 23 Python
Python中使用SAX解析xml实例
Nov 21 Python
使用Python中的tkinter模块作图的方法
Feb 07 Python
Python2随机数列生成器简单实例
Sep 04 Python
python使用SMTP发送qq或sina邮件
Oct 21 Python
python列表的增删改查实例代码
Jan 30 Python
python配置grpc环境
Jan 01 Python
详解Python_shutil模块
Mar 15 Python
利用Python实现kNN算法的代码
Aug 16 Python
使用Python提取文本中含有特定字符串的方法示例
Dec 09 Python
python爬虫beautifulsoup库使用操作教程全解(python爬虫基础入门)
Feb 19 Python
Django中celery的使用项目实例
Jul 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中使用与Perl兼容的正则表达式
2006/11/26 PHP
php加密解密函数authcode的用法详细解析
2013/10/28 PHP
解决ThinkPHP关闭调试模式时报错的问题汇总
2015/04/22 PHP
PHP防盗链的基本思想 防盗链的设置方法
2015/09/25 PHP
js 调用本地exe的例子(支持IE内核的浏览器)
2012/12/26 Javascript
Js参数值中含有单引号或双引号问题的解决方法
2013/11/06 Javascript
jquery改变disabled的boolean状态的三种方法
2013/12/13 Javascript
javascript arguments使用示例
2014/12/16 Javascript
AngularJS内置指令
2015/02/04 Javascript
jQuery聚合函数实例
2015/05/21 Javascript
js实现汉字排序的方法
2015/07/23 Javascript
javascript中setTimeout使用指南
2015/07/26 Javascript
js简单实现标签云效果实例
2015/08/06 Javascript
jquery仿QQ登录账号选择下拉框效果
2016/03/22 Javascript
基于jquery编写的放大镜插件
2016/03/23 Javascript
用jQuery获取table中行id和td值的实现代码
2016/05/19 Javascript
javascript实现标签切换代码示例
2016/05/22 Javascript
JS中闭包的经典用法小结(2则示例)
2016/12/28 Javascript
ng-options和ng-checked在表单中的高级运用(推荐)
2017/01/21 Javascript
React Native开发封装Toast与加载Loading组件示例
2018/09/08 Javascript
基于VUE实现的九宫格抽奖功能
2018/09/30 Javascript
JS/HTML5游戏常用算法之碰撞检测 包围盒检测算法详解【矩形情况】
2018/12/13 Javascript
使用VUE+iView+.Net Core上传图片的方法示例
2019/01/04 Javascript
解决layer弹出层msg的文字不显示的问题
2019/09/11 Javascript
详解如何修改 node_modules 里的文件
2020/05/22 Javascript
精确查找PHP WEBSHELL木马的方法(1)
2011/04/12 Python
Python中使用haystack实现django全文检索搜索引擎功能
2017/08/26 Python
python使用pil库实现图片合成实例代码
2018/01/20 Python
Python实现的井字棋(Tic Tac Toe)游戏示例
2018/01/31 Python
python3解析库lxml的安装与基本使用
2018/06/27 Python
Python smtp邮件发送模块用法教程
2020/06/15 Python
Python collections模块的使用方法
2020/10/09 Python
修理厂厂长岗位职责
2014/01/30 职场文书
诚实守信演讲稿
2014/09/01 职场文书
六五普法宣传标语
2014/10/06 职场文书
爱的教育读书笔记
2015/06/26 职场文书