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 相关文章推荐
压缩包密码破解示例分享(类似典破解)
Jan 17 Python
深入解析Python中函数的参数与作用域
Mar 20 Python
对python cv2批量灰度图片并保存的实例讲解
Nov 09 Python
Python OS模块实例详解
Apr 15 Python
详解Python3 基本数据类型
Apr 19 Python
Golang GBK转UTF-8的例子
Aug 26 Python
python装饰器使用实例详解
Dec 14 Python
python无序链表删除重复项的方法
Jan 17 Python
PyQt5中向单元格添加控件的方法示例
Mar 24 Python
完美解决jupyter由于无法import新包的问题
May 26 Python
Python调用JavaScript代码的方法
Oct 27 Python
Python爬虫框架之Scrapy中Spider的用法
Jun 28 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实现货币换算的方法
2014/11/29 PHP
php中使用base HTTP验证的方法
2015/04/20 PHP
使用PHP实现微信摇一摇周边红包
2016/01/04 PHP
PHP将二维数组某一个字段相同的数组合并起来的方法
2016/02/26 PHP
PHP单例模式数据库连接类与页面静态化实现方法
2019/03/20 PHP
YUI Compressor压缩JavaScript原理及微优化
2013/01/07 Javascript
js鼠标滑轮滚动事件绑定的简单实例(兼容主流浏览器)
2014/01/14 Javascript
JavaScript字符串对象slice方法入门实例(用于字符串截取)
2014/10/16 Javascript
node.js中的fs.createReadStream方法使用说明
2014/12/17 Javascript
jQuery应用之jQuery链用法实例
2015/01/19 Javascript
微信WeixinJSBridge API使用实例
2015/05/25 Javascript
基于jQuery实现的菜单切换效果
2015/10/16 Javascript
一款简单的jQuery图片标注效果附源码下载
2016/03/22 Javascript
JavaScript高仿支付宝倒计时页面及代码实现
2016/10/21 Javascript
javascript中的try catch异常捕获机制用法分析
2016/12/14 Javascript
jquery.zclip轻量级复制失效问题
2017/01/08 Javascript
微信小程序 详解Page中data数据操作和函数调用
2017/01/12 Javascript
bootstrap插件treeview实现全选父节点下所有子节点和反选功能
2017/07/21 Javascript
js实现自定义右键菜单
2020/05/18 Javascript
vuecli项目构建SSR服务端渲染的实现
2020/10/30 Javascript
[42:50]NB vs VP 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
pygame学习笔记(2):画点的三种方法和动画实例
2015/04/15 Python
用python实现简单EXCEL数据统计的实例
2017/01/24 Python
python爬虫入门教程--利用requests构建知乎API(三)
2017/05/25 Python
Django model 中设置联合约束和联合索引的方法
2019/08/06 Python
python matplotlib如何给图中的点加标签
2019/11/14 Python
python统计字符的个数代码实例
2020/02/07 Python
如何使用Python自动生成报表并以邮件发送
2020/10/15 Python
Python系统公网私网流量监控实现流程
2020/11/23 Python
如何利用python正则表达式匹配版本信息
2020/12/09 Python
Python实现给PDF添加水印的方法
2021/01/25 Python
美国男女折扣服饰百货连锁店:Stein Mart
2017/05/02 全球购物
教师党员自我剖析材料
2014/09/29 职场文书
端午节寄语2015
2015/03/23 职场文书
2016年第32个教师节致辞
2015/11/26 职场文书
mysql批量新增和存储的方法实例
2021/04/07 MySQL