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调用新浪微博API项目实践
Jul 28 Python
在Python的Django框架中调用方法和处理无效变量
Jul 15 Python
python PyTorch参数初始化和Finetune
Feb 11 Python
解决PyCharm的Python.exe已经停止工作的问题
Nov 29 Python
5分钟 Pipenv 上手指南
Dec 20 Python
python调用动态链接库的基本过程详解
Jun 19 Python
对Python3中列表乘以某一个数的示例详解
Jul 20 Python
Python学习笔记之Zip和Enumerate用法实例分析
Aug 14 Python
使用turtle绘制五角星、分形树
Oct 06 Python
适合Python初学者的一些编程技巧
Feb 12 Python
卸载tensorflow-cpu重装tensorflow-gpu操作
Jun 23 Python
Python+Appium实现自动化清理微信僵尸好友的方法
Feb 04 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回溯法解决0-1背包问题实例分析
2015/03/23 PHP
php使用Session和文件统计在线人数
2015/07/04 PHP
PHP递归实现层级树状展开
2016/04/01 PHP
JS中彻底删除JSON对象组成的数组中的元素
2020/09/22 PHP
基于JQuery的访问WebService的代码(可访问Java[Xfire])
2010/11/19 Javascript
分享XmlHttpRequest调用Webservice的一点心得
2012/07/20 Javascript
Javascript中产生固定结果的函数优化技巧
2013/01/16 Javascript
css transform 3D幻灯片特效实现步骤解读
2013/03/27 Javascript
JavaScript动态操作表格实例(添加,删除行,列及单元格)
2013/11/25 Javascript
使用jsonp完美解决跨域问题
2014/11/27 Javascript
详解AngularJS中module模块的导入导出
2015/12/10 Javascript
BootStrap实现邮件列表的分页和模态框添加邮件的功能
2016/10/13 Javascript
12个非常有用的JavaScript技巧
2017/05/17 Javascript
详解从Vue.js源码看异步更新DOM策略及nextTick
2017/10/11 Javascript
vue 父组件通过$refs获取子组件的值和方法详解
2019/11/07 Javascript
ant-design-vue中tree增删改的操作方法
2020/11/03 Javascript
了不起的11个JavaScript代码重构最佳实践小结
2021/01/11 Javascript
[01:16:16]DOTA2-DPC中国联赛定级赛 RNG vs Phoenix BO3第二场 1月8日
2021/03/11 DOTA
python实现类似ftp传输文件的网络程序示例
2014/04/08 Python
Python OS模块常用函数说明
2015/05/23 Python
Python实现按特定格式对文件进行读写的方法示例
2017/11/30 Python
flask框架中勾子函数的使用详解
2018/08/01 Python
Python设计模式之状态模式原理与用法详解
2019/01/15 Python
python实现知乎高颜值图片爬取
2019/08/12 Python
python中urllib.request和requests的使用及区别详解
2020/05/05 Python
使用pyplot.matshow()函数添加绘图标题
2020/06/16 Python
咖啡为什么会有酸味?你喝到的咖啡為什麼是酸的?
2021/03/17 冲泡冲煮
Pretty Little Thing爱尔兰:时尚女性服饰
2017/03/27 全球购物
应届生妇产科护士求职信
2013/10/27 职场文书
新闻编辑专业毕业自荐书范文
2014/02/05 职场文书
大学生学期自我鉴定
2014/03/19 职场文书
室内趣味活动方案
2014/08/24 职场文书
2014年工人工作总结
2014/11/25 职场文书
演讲稿之我的初心我的成长
2019/08/12 职场文书
CSS的calc函数用法小结
2022/06/25 HTML / CSS
python语言中pandas字符串分割str.split()函数
2022/08/05 Python