前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Python 自带异步队列的大坑

Python 自带异步队列的大坑

作者头像
青南
发布于 2020-06-04 08:55:25
发布于 2020-06-04 08:55:25
7.6K00
代码可运行
举报
文章被收录于专栏:未闻Code未闻Code
运行总次数:0
代码可运行

我们在使用 Python 的 asyncio 写异步程序的时候,可能会使用asyncio.Queue来实现一个异步队列,通过它来让生产者和消费者进行通信。

但如果你的异步队列没有填写maxsize参数,那么可能会产生让你意料之外的结果。我们来看一段代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import asyncio
import random
import aiohttp


async def producer(queue):
    for _ in range(10):
        sleep_time = random.randint(1, 2)
        await queue.put(sleep_time)


async def consumer(queue):
    while True:
        sleep_time = await queue.get()
        size = queue.qsize()
        print(f'当前队列有:{size} 个元素')
        url = f'http://httpbin.org/delay/{sleep_time}'
        async with aiohttp.ClientSession() as client:
            resp = await client.get(url)
            print(await resp.json())

async def main():
    queue = asyncio.Queue()
    asyncio.create_task(producer(queue))
    con = asyncio.create_task(consumer(queue))
    await con


asyncio.run(main())

这段代码把 producerconsumer分别创建成异步任务,期望实现的效果是生产者不停生产数据放进异步队列,消费者不停从队列读取数据,然后发起网络请求。生产者与消费者利用 IO 等待时间实现并行。

但如果你运行一下这段代码,你会发现一件很奇怪的事情,如下图所示:

当我们的消费者开始消费的时候,队列里面实际上已经有10条数据了!由于图中代码第19行是先读取了一条数据再打印剩余的数量,所以打印的是当前队列有:9 个元素

所以,生产者与消费者根本没有并行。是生产者里面的循环完全运行完成了,才开始运行的消费者!

如果在实际代码中,你的生产者生产了几百万条数据,那么此时所有数据全部都堆放在异步队列里面,很容易就把你的内存撑爆了!

那么这个问题要如何解决呢?实际上非常简单,使用maxsize参数指定异步队列的大小:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
queue = asyncio.Queue(maxsize=3)

我们这里设定为3,再运行看看效果:

看到这里,可能有人会说,这仅仅是生产者先把异步队列堆满,才能进行消费,并没有什么本质区别啊,本质上还是先只有生产者运行,等他跑不动了(队列满了),消费者才能运行,还是没有实现并行啊。

这是由于,在上面的例子中,生产者的速度远远超过消费者的速度,所以才会出现生产者总是堆满队列的问题。

为了说明生产者和消费者能真正利用 IO 等待时间进行并行,我们改一下代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import asyncio
import random
import aiohttp


async def producer(queue):
    for i in range(10):
        await queue.put(i)
        await asyncio.sleep(random.randint(1, 3))


async def consumer(queue):
    while True:
        sleep_time = await queue.get()
        size = queue.qsize()
        print(f'当前队列有:{size} 个元素')
        url = 'http://httpbin.org/delay/2'
        async with aiohttp.ClientSession() as client:
            resp = await client.get(url)
            print(await resp.json())

async def main():
    queue = asyncio.Queue(maxsize=3)
    asyncio.create_task(producer(queue))
    con = asyncio.create_task(consumer(queue))
    await con


asyncio.run(main())

生产者生产数据后,随机休眠1-3秒。而消费者请求的网址总是2秒返回数据。这样一来,有时候生产者快,有时候消费者快。我们来看看运行效果:

可以看到,当生产者快的时候,异步队列里面的数据就会堆积,当消费者快的时候,异步队列里面的数据就会变少。说明生产者与消费者实现了利用 IO 等待时间进行并行操作。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-05-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 未闻Code 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
python-高级协程编程-协程间的通信和数据传输(二)
Queue 是一种常见的协程间通信和数据传输的机制。它是一个先进先出(FIFO)的数据结构,协程可以将数据放入队列中,另一个协程可以从队列中取出数据。
玖叁叁
2023/04/22
5760
Python黑科技之异步编程:玩转事件循环
Python的异步编程是一项极为强大的技术,通过事件循环和协程,你可以实现高效的非阻塞并发操作。在这篇文章中,我们将揭示Python异步编程的黑科技,深入了解事件循环的奥秘,助你在编写异步代码时游刃有余。
dbdocker
2024/02/04
5530
Python异步IO操作,看这个就够了
异步 IO 是一种并发编程设计,Python3.4 开始,已经有专门的标准库 asyncio 来支持异步 IO 操作。你可能会说,我知道并发用多线程,并行用多进程,这里面的知识已经够我掌握的了,异步 IO 又是个什么鬼?本文将会回答该问题,从而使你更加牢固地掌握 Python 的异步 IO 操作方法。
somenzz
2020/11/25
2.9K0
Python异步IO操作,看这个就够了
python-协程并发-多个协程的同步(二)
条件变量是一种常用的协程同步机制,用于在协程之间传递信号。在Python中,我们可以使用asyncio模块中的条件变量来实现协程的同步。asyncio.Condition是一个类似于标准库中Condition的同步原语,用于协调多个协程之间的等待和通信。
玖叁叁
2023/04/21
4350
浅度测评:requests、aiohttp、httpx 我应该用哪一个?
作者 l kingname 来源 l 未闻 Code(ID:itskingname)
andrew_a
2020/02/18
2.3K0
浅度测评:requests、aiohttp、httpx 我应该用哪一个?
性能测试: Python3 利用asynico协程系统构建生产消费模型
今天研究了下python3的新特性 asynico ,试了试 aiohttp 协程效果,单核QPS在500~600之间,性能还可以。
机械视角
2019/10/23
4420
3.异步协程爬取下载网络小说
之前,我们已经通过多线程的方式实现了下载网络小说,参阅文章地址,下面将采用异步携程的方式进行下载。
jiagui
2024/07/08
1190
python-协程并发-多个协程的同步(三)
队列是一种常用的协程同步机制,用于在协程之间传递数据。在Python中,我们可以使用asyncio模块中的队列来实现协程的同步。asyncio.Queue是一个类似于标准库中Queue的同步原语,用于在协程之间传递数据。
玖叁叁
2023/04/21
4730
协程和异步I/O
协程(coroutine)通常又称之为微线程或纤程,它是相互协作的一组子程序(函数)。所谓相互协作指的是在执行函数A时,可以随时中断去执行函数B,然后又中断继续执行函数A。注意,这一过程并不是函数调用(因为没有调用语句),整个过程看似像多线程,然而协程只有一个线程执行。协程通过yield关键字和 send()操作来转移执行权,协程之间不是调用者与被调用者的关系。
用户8442333
2021/05/21
8580
Python异步爬虫与代理完美结合
为了编写一个高性能的异步爬虫,并使用代理IP,我们可以使用以下技术栈:aiohttp (用于异步HTTP请求)、asyncio (用于异步编程)、代理IP可以使用一个代理池,我们从文件中读取或者从API获取。在这里,我们假设代理IP存储在一个文本文件中,每行一个,格式为:http://ip:port 或 http://user:pass@ip:port
华科云商小徐
2025/06/05
1030
剖析灵魂,为什么aiohttp默认的写法那么慢?
在上一篇文章中,我们提到了 aiohttp 官方文档中的默认写法速度与 requests 单线程请求没有什么区别,需要通过使用asyncio.wait来加速 aiohttp 的请求。今天我们来探讨一下这背后的原因。
青南
2019/12/25
1.9K0
剖析灵魂,为什么aiohttp默认的写法那么慢?
【Python爬虫实战】深入理解Python异步编程:从协程基础到高效爬虫实现
随着网络和数据的迅速发展,越来越多的场景需要高效处理大量请求和数据。传统的同步编程模式在处理I/O密集型任务时会浪费大量等待时间,而Python的异步编程技术提供了一种更高效的方式。本文从Python异步编程的基础概念出发,深入讲解协程、asyncio库及其核心功能。通过详细的代码示例与解释,我们将逐步探索异步编程的应用场景
易辰君
2024/11/07
2010
Python协程-asyncio、async/await
上面的代码也可以这样写,将15到21行换成一行await asyncio.gather(a(), b())也能实现类似的效果,await asyncio.gather 会并发运行传入的可等待对象(Coroutine、Task、Future)。
Cloud-Cloudys
2020/07/07
3.3K0
aiohttp 异步http请求-2.post 请求application/json和data
前言 aiohttp 发送post请求,body类型的常见的类型传参: application/json application/x-www-form-urlencode application/json POST 请求接口报文示例,Content-Type类型是application/json POST /api/v1/login/ HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-
上海-悠悠
2022/04/21
6.7K0
一日一技:在Python 的线程中运行协程
在一篇文章理解Python异步编程的基本原理这篇文章中,我们讲到,如果在异步代码里面又包含了一段非常耗时的同步代码,异步代码就会被卡住。
青南
2020/02/26
4.4K0
一日一技:在Python 的线程中运行协程
Python异步编程与事件循环的实战指南
异步编程是一种高效的编程方式,特别适用于I/O密集型任务,如网络请求、文件读取等。Python中,异步编程主要通过asyncio模块实现。asyncio提供了事件循环、协程和任务等关键概念,使得编写异步代码更加直观和高效。本文将详细介绍Python异步编程与事件循环的基本概念和高级用法,包含具体的示例代码,帮助更好地理解和应用这些技术。
sergiojune
2024/08/12
2920
Python异步编程与事件循环的实战指南
【Python】教你彻底了解Python中的并发编程
随着计算机处理能力的不断提升和多核处理器的普及,并发编程变得越来越重要。并发编程可以使程序同时执行多个任务,从而提高程序的性能和响应速度。在Python中,有多种方式可以实现并发编程,包括线程、进程和异步编程。在这篇文章中,我们将深入探讨Python中的并发编程,涵盖其基本概念、线程与进程、多线程编程、多进程编程、异步编程以及并发编程的实际应用示例。
E绵绵
2025/05/25
1980
一日一技:装饰器如何装饰异步函数
在 Python 开发的工程中,我们常常使用装饰器来优化代码,例如一个打印日志的装饰器:
青南
2020/02/19
4K1
一日一技:装饰器如何装饰异步函数
python协程
https://docs.python.org/zh-cn/3/library/asyncio.html
润森
2019/11/10
5200
大型fastapi项目实战 高并发请求神器之aiohttp(上) [建议收藏]
在 Python 众多的 HTTP 客户端中,最有名的莫过于 requests、aiohttp 和 httpx。在不借助其他第三方库的情况下,requests 只能发送同步请求;aiohttp 只能发送异步请求;httpx 既能发送同步请求,又能发送异步请求。在并发量大的情况下,如何高效的处理数据,异步是我们的优选,今天我们主要详解的是在生产环境广泛使用的 aiohttp。
python编程从入门到实践
2021/02/04
10.7K0
推荐阅读
相关推荐
python-高级协程编程-协程间的通信和数据传输(二)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验