python 异步async库的使用说明


Posted in Python onMay 04, 2020

在学习asyncio之前,先理清楚同步/异步的概念:

同步是指完成事务的逻辑,先执行第一个事务,如果阻塞了,会一直等待,直到这个事务完成,再执行第二个事务,顺序执行

异步是和同步相对的,异步是指在处理调用这个事务的之后,不会等待这个事务的处理结果,直接处理第二个事务去了,通过状态、通知、回调来通知调用者处理结果

asyncio函数:

异步IO采用消息循环的模式,重复“读取消息—处理消息”的过程,也就是说异步IO模型”需要一个消息循环,在消息循环中,主线程不断地重复“读取消息-处理消息”这一过程。

event_loop 事件循环:程序开启一个无限的循环,程序员会把一些函数注册到事件循环上。当满足事件发生的时候,调用相应的协程函数。

coroutine 协程:协程对象,指一个使用async关键字定义的函数,它的调用不会立即执行函数,而是会返回一个协程对象。协程对象需要注册到事件循环,由事件循环调用。

task 任务:一个协程对象就是一个原生可以挂起的函数,任务则是对协程进一步封装,其中包含任务的各种状态。

async/await 关键字: 用于定义协程的关键字,async定义一个协程,await用于挂起阻塞的异步调用接口。

一、asyncio

下面通过举例来对比同步代码和异步代码编写方面的差异,其次看下两者性能上的差距,使用asyncio.sleep(1)模拟耗时1秒的io操作。

同步代码:

import time

def hello():
  time.sleep(1)

def run():
  for i in range(5):
    hello()
    print('Hello World:%s' % time.time()) 
if __name__ == '__main__':
  run()

Hello World:1536842494.2786784
Hello World:1536842495.2796268
Hello World:1536842496.2802596
Hello World:1536842497.2804587
Hello World:1536842498.2812462

异步代码:

import time
import asyncio

# 定义异步函数
async def hello():
  print('Hello World:%s' % time.time())
  #必须使用await,不能使用yield from;如果是使用yield from ,需要采用@asyncio.coroutine相对应
  await asyncio.sleep(1)  
  print('Hello wow World:%s' % time.time())

def run():
  tasks = []
  for i in range(5):
    tasks.append(hello())
  loop.run_until_complete(asyncio.wait(tasks))

loop = asyncio.get_event_loop()
if __name__ =='__main__':
  run()

Hello World:1536855050.1950748
Hello World:1536855050.1950748
Hello World:1536855050.1950748
Hello World:1536855050.1960726
Hello World:1536855050.1960726
(暂停约1秒)
Hello wow World:1536855051.1993241
Hello wow World:1536855051.1993241
Hello wow World:1536855051.1993241
Hello wow World:1536855051.1993241
Hello wow World:1536855051.1993241

async def 用来定义异步函数,其内部有异步操作。每个线程有一个事件循环,主线程调用asyncio.get_event_loop()时会创建事件循环,把异步的任务丢给这个循环的run_until_complete()方法,事件循环会安排协同程序的执行。

上述程序中,hello()会首先打印出Hello world!,然后,yield from语法可以让我们方便地调用另一个generator。

由于await asyncio.sleep(1)也是一个coroutine,所以线程不会等待asyncio.sleep(1),而是直接中断并执行下一个消息循环。

当asyncio.sleep(1)返回时,线程就可以从yield from拿到返回值(此处是None),然后接着执行下一行语句。

把asyncio.sleep(1)看成是一个耗时1秒的IO操作,在此期间,主线程并未等待,而是去执行EventLoop中其他可以执行的coroutine了,因此可以实现并发执行。

asyncio操作的总结:

async def hello(): 定义async异步函数,中间可以添加await async.sleep(N) 来设定中断并执行下一个循环消息

tasks = [] 任务则是对协程进一步封装,其中包含任务的各种状态。即多个coroutine函数可以封装成一组Task然后并发执行

loop = asyncio.get_event_loop() #获取“事件循环”对象

loop.run_until_complete(asyncio.wait(tasks)) #通过事件循环,去调用协程函数

loop.close() 结束时间循环

二、aiohttp

如果需要并发http请求,通常是用requests,但requests是同步的库,如果想异步的话需要引入aiohttp。

这里引入一个类,from aiohttp import ClientSession,首先要建立一个session对象,然后用session对象去打开网页。

session可以进行多项操作,比如post, get, put, head等。

基本用法:

async with ClientSession() as session:

async with session.get(url) as response:

aiohttp异步实现的例子:

import asyncio
from aiohttp import ClientSession

tasks = []
url = "https://www.baidu.com/{}"
async def hello(url):
  async with ClientSession() as session:
    async with session.get(url) as response:
      response = await response.read()
      print(response)

if __name__ == '__main__':
  loop = asyncio.get_event_loop()
  loop.run_until_complete(hello(url))

首先async def 关键字定义了这是个异步函数,await 关键字加在需要等待的操作前面,response.read()等待request响应,是个耗IO操作。然后使用ClientSession类发起http请求。

多链接异步访问

如果我们需要请求多个URL该怎么办呢,同步的做法访问多个URL只需要加个for循环就可以了。但异步的实现方式并没那么容易,在之前的基础上需要将hello()包装在asyncio的Future对象中,然后将Future对象列表作为任务传递给事件循环。

import time
import asyncio
from aiohttp import ClientSession

tasks = []
url = "https://www.baidu.com/{}"
async def hello(url):
  async with ClientSession() as session:
    async with session.get(url) as response:
      response = await response.read()
      print('Hello World:%s' % time.time())

def run():
  for i in range(5):
    task = asyncio.ensure_future(hello(url.format(i)))
    tasks.append(task)


if __name__ == '__main__':
  loop = asyncio.get_event_loop()
  run()
  loop.run_until_complete(asyncio.wait(tasks))

Hello World:1536843566.064149
Hello World:1536843566.070586
Hello World:1536843566.0769563
Hello World:1536843566.0779328
Hello World:1536843566.0799286

·收集http响应

好了,上面介绍了访问不同链接的异步实现方式,但是我们只是发出了请求,如果要把响应一一收集到一个列表中,最后保存到本地或者打印出来要怎么实现呢,可通过asyncio.gather(*tasks)将响应全部收集起来

import time
import asyncio
from aiohttp import ClientSession

tasks = []
url = "https://www.baidu.com/{}"
async def hello(url):
  async with ClientSession() as session:
    async with session.get(url) as response:
#      print(response)
      print('Hello World:%s' % time.time())
      return await response.read()

def run():
  for i in range(5):
    task = asyncio.ensure_future(hello(url.format(i)))
    tasks.append(task)
  result = loop.run_until_complete(asyncio.gather(*tasks))
  print(result)

if __name__ == '__main__':
  loop = asyncio.get_event_loop()
  run()

Hello World:1536843488.678779
Hello World:1536843488.6797836
Hello World:1536843488.6867576
Hello World:1536843488.6877556
Hello World:1536843488.6877556

以上这篇python 异步async库的使用说明就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python编程之属性和方法实例详解
May 19 Python
python中print()函数的“,”与java中System.out.print()函数中的“+”功能详解
Nov 24 Python
python xlsxwriter创建excel图表的方法
Jun 11 Python
对Python的zip函数妙用,旋转矩阵详解
Dec 13 Python
python 提取key 为中文的json 串方法
Dec 31 Python
python使用正则筛选信用卡
Jan 27 Python
解决webdriver.Chrome()报错:Message:'chromedriver' executable needs to be in Path
Jun 12 Python
python logging日志模块原理及操作解析
Oct 12 Python
可视化pytorch 模型中不同BN层的running mean曲线实例
Jun 24 Python
python 绘制场景热力图的示例
Sep 23 Python
python os.listdir()乱码解决方案
Jan 31 Python
Python selenium的这三种等待方式一定要会!
Jun 10 Python
Python插件机制实现详解
May 04 #Python
python3+selenium获取页面加载的所有静态资源文件链接操作
May 04 #Python
解决IDEA 的 plugins 搜不到任何的插件问题
May 04 #Python
python3 sleep 延时秒 毫秒实例
May 04 #Python
Python并发concurrent.futures和asyncio实例
May 04 #Python
Python 中由 yield 实现异步操作
May 04 #Python
python 双循环遍历list 变量判断代码
May 04 #Python
You might like
BBS(php & mysql)完整版(二)
2006/10/09 PHP
不使用php api函数实现数组的交换排序示例
2014/04/13 PHP
destoon设置自定义搜索的方法
2014/06/21 PHP
mysql_connect localhost和127.0.0.1的区别(网络层阐述)
2015/03/26 PHP
PHP结合Jquery和ajax实现瀑布流特效
2016/01/07 PHP
PHP实现Google plus的好友拖拽分组效果
2016/10/21 PHP
PHP输出图像imagegif、imagejpeg与imagepng函数用法分析
2016/11/14 PHP
PHP实现判断数组是一维、二维或几维的方法
2017/02/06 PHP
yii插入数据库防并发的简单代码
2017/05/27 PHP
jquery之Document元素选择器篇
2008/08/14 Javascript
javascript打开word文档的方法
2014/04/16 Javascript
js贪吃蛇网页版游戏特效代码分享(挑战十关)
2015/08/24 Javascript
原生JS实现垂直手风琴效果
2017/02/19 Javascript
nodejs实现简单的gulp打包
2017/12/21 NodeJs
JS处理一些简单计算题
2018/02/24 Javascript
vue移动端实现红包雨效果
2020/06/23 Javascript
jQuery实现基本隐藏与显示效果的方法详解
2018/09/05 jQuery
node.js实现微信开发之获取用户授权
2019/03/18 Javascript
从理论角度讨论JavaScript闭包
2019/04/03 Javascript
Vue移动端右滑屏幕返回上一页附源码下载
2019/06/26 Javascript
jQuery实现评论模块
2020/08/19 jQuery
[02:34]DOTA2英雄基础教程 幽鬼
2014/01/02 DOTA
让 python 命令行也可以自动补全
2014/11/30 Python
python操作 hbase 数据的方法
2016/12/18 Python
python与php实现分割文件代码
2017/03/06 Python
python3判断url链接是否为404的方法
2018/08/10 Python
利用ctypes获取numpy数组的指针方法
2019/02/12 Python
python如何通过闭包实现计算器的功能
2020/02/22 Python
如何用Python 加密文件
2020/09/10 Python
草莓巧克力:Shari’s Berries
2017/02/07 全球购物
新西兰网上购物,折扣店:BestDeals.co.nz
2019/03/20 全球购物
《开国大典》教学反思
2014/04/19 职场文书
医院病假条范文
2015/08/17 职场文书
使用Django实现商城验证码模块的方法
2021/06/01 Python
基于Python实现对比Exce的工具
2022/04/07 Python
Android移动应用开发指南之六种布局详解
2022/09/23 Java/Android