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实现生成简单的Makefile文件代码示例
Mar 10 Python
在Python的Flask中使用WTForms表单框架的基础教程
Jun 07 Python
Django 2.0版本的新特性抢先看!
Jan 05 Python
Python+tkinter使用40行代码实现计算器功能
Jan 30 Python
python 对给定可迭代集合统计出现频率,并排序的方法
Oct 18 Python
Scrapy-Redis结合POST请求获取数据的方法示例
May 07 Python
python使用tkinter库实现五子棋游戏
Jun 18 Python
Pytorch evaluation每次运行结果不同的解决
Jan 02 Python
Python小整数对象池和字符串intern实例解析
Mar 21 Python
python画环形图的方法
Mar 25 Python
python 爬取天气网卫星图片
Jun 07 Python
Python Pandas常用函数方法总结
Jun 15 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 CURL CURLOPT参数说明(curl_setopt)
2013/09/30 PHP
CI框架中集成CKEditor编辑器的教程
2014/06/09 PHP
php发送html格式文本邮件的方法
2015/06/10 PHP
php实现URL加密解密的方法
2016/11/17 PHP
jQuery 打造动态渐变按钮 详细图文教程
2010/04/25 Javascript
javascript奇异的arguments分析
2010/10/20 Javascript
了解jQuery技巧来提高你的代码(个人觉得那个jquery的手册很不错)
2012/02/10 Javascript
JavaScript获取FCK编辑器信息的具体方法
2013/07/12 Javascript
鼠标滚轮改变图片大小的示例代码
2013/11/20 Javascript
jQuery插件StickUp实现网页导航置顶
2015/04/12 Javascript
JavaScript中数据类型转换总结
2016/12/25 Javascript
使用ef6创建oracle数据库的实体模型遇到的问题及解决方案
2017/11/09 Javascript
使用express搭建一个简单的查询服务器的方法
2018/02/09 Javascript
Python中的赋值、浅拷贝、深拷贝介绍
2015/03/09 Python
Python松散正则表达式用法分析
2016/04/29 Python
flask session组件的使用示例
2018/12/25 Python
python列表使用实现名字管理系统
2019/01/30 Python
PyCharm-错误-找不到指定文件python.exe的解决方法
2019/07/01 Python
pandas取出重复数据的方法
2019/07/04 Python
django使用admin站点上传图片的实例
2019/07/28 Python
简单了解python filter、map、reduce的区别
2020/01/14 Python
使用Python开发个京东上抢口罩的小实例(仅作技术研究学习使用)
2020/03/10 Python
Python request使用方法及问题总结
2020/04/26 Python
使用Keras训练好的.h5模型来测试一个实例
2020/07/06 Python
基于opencv的selenium滑动验证码的实现
2020/07/24 Python
STUBHUB日本:购买和出售全球活动门票
2018/07/01 全球购物
乌克兰网上服装店:Bolf.ua
2018/10/30 全球购物
苹果台湾官网:Apple台湾
2019/01/05 全球购物
Viking Direct爱尔兰:办公用品和家具
2019/11/21 全球购物
洗车工岗位职责
2014/03/15 职场文书
有关爱国演讲稿
2014/05/07 职场文书
企业财务人员岗位职责
2015/04/14 职场文书
纯CSS实现hover图片pop-out弹出效果的实例代码
2021/04/16 HTML / CSS
pandas 实现将NaN转换为None
2021/05/14 Python
阿里云服务器搭建Php+Apache运行环境的详细过程
2021/05/15 PHP
python opencv检测直线 cv2.HoughLinesP的实现
2021/06/18 Python