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 14 Python
python之Socket网络编程详解
Sep 29 Python
python下如何查询CS反恐精英的服务器信息
Jan 17 Python
Win7下Python与Tensorflow-CPU版开发环境的安装与配置过程
Jan 04 Python
Python拼接字符串的7种方法总结
Nov 01 Python
Python read函数按字节(字符)读取文件的实现
Jul 03 Python
Python 实现数据结构-循环队列的操作方法
Jul 17 Python
python 使用shutil复制图片的例子
Dec 13 Python
PyTorch中permute的用法详解
Dec 30 Python
在 Python 中接管键盘中断信号的实现方法
Feb 04 Python
Python输出指定字符串的方法
Feb 06 Python
jupyternotebook 撤销删除的操作方式
Apr 17 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
PHP教程 基本语法
2009/10/23 PHP
php 过滤器实现代码
2010/08/09 PHP
php魔术变量用法实例详解
2014/11/13 PHP
PHP检测用户语言的方法
2015/06/15 PHP
js常见表单应用技巧
2008/01/09 Javascript
jQuery 遍历-nextUntil()方法以及prevUntil()方法的使用介绍
2013/04/26 Javascript
详解JavaScript UTC时间转换方法
2016/01/07 Javascript
jQuery使用cookie与json简单实现购物车功能
2016/04/15 Javascript
javascript断点调试心得分享
2016/04/23 Javascript
详解JavaScript中this关键字的用法
2016/05/26 Javascript
详解ES6之async+await 同步/异步方案
2017/09/19 Javascript
浅析Node.js非对称加密方法
2018/01/29 Javascript
vue axios 表单提交上传图片的实例
2018/03/16 Javascript
tracking.js页面人脸识别插件使用方法
2020/04/16 Javascript
JS数组中对象去重操作示例
2019/06/04 Javascript
JQuery样式与属性设置方法分析
2019/12/07 jQuery
vue a标签点击实现赋值方式
2020/09/07 Javascript
[00:34]TI7不朽珍藏III——纯金地穴编织者饰品展示
2017/07/15 DOTA
[01:06:26]全国守擂赛第二周 Team Coach vs DeMonsTer
2020/04/28 DOTA
Python实例之wxpython中Frame使用方法
2014/06/09 Python
Python使用shelve模块实现简单数据存储的方法
2015/05/20 Python
再谈Python中的字符串与字符编码(推荐)
2016/12/14 Python
详解python3中zipfile模块用法
2018/06/18 Python
python 三元运算符使用解析
2019/09/16 Python
python绘制封闭多边形教程
2020/02/18 Python
canvas绘制树形结构可视图形的实现
2020/04/03 HTML / CSS
奥地利汽车配件店:Pkwteile.at
2017/03/10 全球购物
世界上最大的隐形眼镜商店:1-800 Contacts
2018/11/03 全球购物
Under Armour瑞典官方网站:美国高端运动科技品牌
2018/11/21 全球购物
编写一子程序,将一链表倒序,即使链表表尾变表头,表头变表尾
2016/02/10 面试题
"引用"与指针的区别是什么
2016/09/07 面试题
下面关于"联合"的题目的输出是什么
2013/08/06 面试题
诺思信科技(南京)有限公司.NET笔试题答案
2013/07/06 面试题
医学毕业生自我鉴定
2013/10/30 职场文书
二年级作文之动物作文
2019/11/13 职场文书
Vue全局事件总线你了解吗
2022/02/24 Vue.js