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中的引用和拷贝浅析
Nov 22 Python
浅析Python中元祖、列表和字典的区别
Aug 17 Python
使用Python对Access读写操作
Mar 30 Python
python机器学习库常用汇总
Nov 15 Python
python脚本生成caffe train_list.txt的方法
Apr 27 Python
Django进阶之CSRF的解决
Aug 01 Python
Python3与fastdfs分布式文件系统如何实现交互
Jun 23 Python
vscode配置anaconda3的方法步骤
Aug 08 Python
Python3合并两个有序数组代码实例
Aug 11 Python
10款最佳Python开发工具推荐,每一款都是神器
Oct 15 Python
Python读取图像并显示灰度图的实现
Dec 01 Python
Python实现数据的序列化操作详解
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新手上路(十)
2006/10/09 PHP
PHP网站开发中常用的8个小技巧
2015/02/13 PHP
php微信支付接口开发程序
2016/08/02 PHP
Javascript中valueOf与toString区别浅析
2013/03/19 Javascript
jQuery中animate用法实例分析
2015/03/09 Javascript
jQuery+PHP实现可编辑表格字段内容并实时保存
2015/10/09 Javascript
浅析javascript的return语句
2015/12/15 Javascript
Javascript中常用的检测方法小结
2016/10/08 Javascript
BootStrap中Table分页插件使用详解
2016/10/09 Javascript
js阻止移动端页面滚动的两种方法
2017/01/25 Javascript
微信小程序分页加载的实例代码
2017/07/11 Javascript
Vuejs 单文件组件实例详解
2018/02/09 Javascript
JS如何实现封装列表右滑动删除收藏按钮
2020/07/23 Javascript
Vue开发中常见的套路和技巧总结
2020/11/24 Vue.js
[05:29]2014DOTA2国际邀请赛 赛后专访:LGDNewbee顺利过关
2014/07/13 DOTA
[53:15]2018DOTA2亚洲邀请赛3月29日 小组赛A组 KG VS OG
2018/03/30 DOTA
探究python中open函数的使用
2016/03/01 Python
python的变量与赋值详细分析
2017/11/08 Python
python 多个参数不为空校验方法
2019/02/14 Python
Python3中_(下划线)和__(双下划线)的用途和区别
2019/04/26 Python
Python OpenCV 调用摄像头并截图保存功能的实现代码
2019/07/02 Python
django多对多表的创建,级联删除及手动创建第三张表
2019/07/25 Python
Python定时任务随机时间执行的实现方法
2019/08/14 Python
Python unittest单元测试框架及断言方法
2020/04/15 Python
获取python运行输出的数据并解析存为dataFrame实例
2020/07/07 Python
用Python自动清理电脑内重复文件,只要10行代码(自动脚本)
2021/01/09 Python
中国综合网上购物商城:苏宁易购
2016/08/09 全球购物
IdealFit官方网站:女性蛋白质、补充剂和运动服装
2019/03/24 全球购物
初三家长会邀请函
2014/01/18 职场文书
先进集体事迹材料
2014/02/17 职场文书
《台湾的蝴蝶谷》教学反思
2014/02/20 职场文书
出国英文推荐信
2014/05/10 职场文书
英文道歉信
2015/01/20 职场文书
2019自荐信该如何写呢?
2019/07/05 职场文书
Golang: 内建容器的用法
2021/05/05 Golang
原生Javascript+HTML5一步步实现拖拽排序
2021/06/12 Javascript