深入理解Python中的并发与异步的结合使用

​ 在上一篇文章中,我们讨论了异步编程中的性能优化技巧,并简单介绍了triocurio库。今天,我们将深入探讨如何将并发编程与异步编程结合使用,并详细讲解如何利用triocurio库优化异步编程中的性能。

文章目录

        • 并发与异步编程的区别与联系
        • 并发编程与异步编程的优缺点
          • 并发编程
          • 异步编程
        • 如何在同一个程序中同时使用 `threading`、`multiprocessing` 和 `asyncio`
          • 使用 `threading` 和 `asyncio`
        • 深入使用 `trio` 库
          • 基本使用
          • 高级功能:取消与超时
        • 深入使用 `curio` 库
          • 基本使用
          • 高级功能:任务取消与超时
      • 性能优化技巧
      • 结语

并发与异步编程的区别与联系

并发编程和异步编程都是处理多任务的有效手段,但它们的实现方式和适用场景有所不同:

  • 并发编程:通过线程或进程来同时执行多个任务,适用于CPU密集型任务;
  • 异步编程:通过事件循环和协程来调度任务,适用于I/O密集型任务。

结合使用并发和异步编程,可以同时处理CPU密集型和I/O密集型任务,提升程序整体性能。

并发编程与异步编程的优缺点
并发编程
  • 优点
    • 可以充分利用多核CPU的优势,提高程序的执行效率;
    • 适用于需要大量计算的任务,例如数据处理、图像处理等。
  • 缺点
    • 线程和进程的管理和调度较为复杂,需要处理同步、锁等问题;
    • 创建和销毁线程或进程会有一定的开销。
异步编程
  • 优点
    • 适用于I/O密集型任务,可以在等待I/O操作完成时执行其他任务,提高资源利用率;
    • 代码更加简洁,逻辑清晰。
  • 缺点
    • 仅能在单线程中运行,不能利用多核CPU的优势;
    • 对于CPU密集型任务效果不佳。
如何在同一个程序中同时使用 threadingmultiprocessingasyncio

在同一个程序中,我们可以利用 threadingmultiprocessing 提供并发能力,同时使用 asyncio 实现异步I/O操作:

使用 threadingasyncio
import asyncio
import threadingasync def async_task():print("Starting async task")await asyncio.sleep(2)print("Async task completed")def sync_task(loop):print("Starting sync task")loop.run_until_complete(async_task())print("Sync task completed")loop = asyncio.get_event_loop()
thread = threading.Thread(target=sync_task, args=(loop,))
thread.start()
thread.join()

使用 multiprocessingasyncio

import asyncio
import multiprocessingasync def async_task():print("Starting async task")await asyncio.sleep(2)print("Async task completed")def sync_task():loop = asyncio.new_event_loop()asyncio.set_event_loop(loop)loop.run_until_complete(async_task())if __name__ == "__main__":process = multiprocessing.Process(target=sync_task)process.start()process.join()
深入使用 trio

trio对异步编程提供了更友好的API,以及更加健壮的错误处理机制;它简化了异步编程的许多复杂性,特别是对于需要多个并发任务的场景:

基本使用
import trio
import asksasync def fetch(url):response = await asks.get(url)return response.textasync def main():urls = ['http://example.com', 'http://example.org', 'http://example.net']async with trio.open_nursery() as nursery:for url in urls:nursery.start_soon(fetch, url)trio.run(main)
高级功能:取消与超时

trio中,可以轻松地对任务进行取消和超时操作:

import trioasync def long_running_task():try:print("Task started")await trio.sleep(10)print("Task completed")except trio.Cancelled:print("Task was cancelled")async def main():async with trio.open_nursery() as nursery:nursery.start_soon(long_running_task)await trio.sleep(5)nursery.cancel_scope.cancel()trio.run(main)

异常处理与重试机制

import trio
import asksasync def fetch_with_retry(url, retries=3):for attempt in range(retries):try:response = await asks.get(url)return response.textexcept Exception as e:print(f"Attempt {attempt + 1} failed: {e}")await trio.sleep(2)raise Exception(f"Failed to fetch {url} after {retries} attempts")async def main():urls = ['http://example.com', 'http://example.org', 'http://example.net']async with trio.open_nursery() as nursery:for url in urls:nursery.start_soon(fetch_with_retry, url)trio.run(main)
深入使用 curio

curio 是另一个异步编程库,主要强调简单性和高性能,适用于需要低延迟和高吞吐量的场景:

基本使用
import curio
import httpxasync def fetch(url):async with httpx.AsyncClient() as client:response = await client.get(url)return response.textasync def main():urls = ['http://example.com', 'http://example.org', 'http://example.net']tasks = [fetch(url) for url in urls]results = await curio.gather(tasks)for result in results:print(result[:100])if __name__ == "__main__":curio.run(main)
高级功能:任务取消与超时

curio 和trio一样提供了强大的任务管理功能,其中也包括对任务取消和超时操作的处理:

import curioasync def long_running_task():try:print("Task started")await curio.sleep(10)print("Task completed")except curio.CancelledError:print("Task was cancelled")async def main():task = await curio.spawn(long_running_task)await curio.sleep(5)await task.cancel()if __name__ == "__main__":curio.run(main)

使用信号与事件进行任务同步

import curio![](https://files.mdnice.com/user/68804/a9f7fe95-2fc1-4c87-963a-cdbf8c34108b.jpg)async def producer(event):print("Producer sleeping")await curio.sleep(5)print("Producer setting event")await event.set()async def consumer(event):print("Consumer waiting for event")await event.wait()print("Consumer got event")async def main():event = curio.Event()await curio.gather(producer(event), consumer(event))if __name__ == "__main__":curio.run(main)

性能优化技巧

通过结合并发和异步编程技术,以及使用triocurio库,我们可以在处理大量I/O密集型任务时获得显著的性能提升,以下是我在工作中常用的一些性能优化技巧:

  1. 限制并发请求数量:使用信号量(semaphore)限制同时进行的请求数量,防止过多的请求导致系统资源枯竭;
  2. 分块处理任务:将任务划分为多个块,分别进行处理,避免一次性处理大量任务导致的性能问题;
  3. 使用连接池:复用连接,减少连接建立和销毁的开销;
  4. 合理设置超时时间:为每个请求设置合理的超时时间,防止由于某些请求超时导致整个任务的延迟;
  5. 异步I/O操作:尽量使用异步I/O操作,避免阻塞主线程。

结语

通过本文的介绍,我们深入学习了如何将并发编程与异步编程结合使用,以最大化程序的性能和效率。结合使用 threadingmultiprocessingasyncio 可以同时处理CPU密集型和I/O密集型任务,提升程序整体性能,希望这些技巧能帮助你在实际项目中编写出高效、稳定的代码!
如果你对计算机相关技术有更多的兴趣,想要持续的探索,请关注我的公众号哟!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/32044.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构与算法】二叉树的性质 详解

在二叉树的第i层上至多有多少个结点。 在二叉树的第 i 层上至多有 2 i − 1 2^{i-1} 2i−1 个结点(i≥1)。 深度为 K的二叉树至多有多少个结点。 深度为 k 的二叉树上至多含 2 k − 1 2^k - 1 2k−1 个结点(k≥1)。 在一颗二叉树中, 其叶子结点数n0和度为二的结点数n2之间…

安装CDH时报错:Parcel 不可用于操作系统分配 RHEL7,原因与解决办法~

报错信息: 解决办法与思路: 1、检查CDH包的后缀名称,Redhat与Centos安装时不需要修改后缀名称,麒麟系统安装时才需要修改。 2、目录里面需要有xxx.parcel xxx.parcel.sha manifest.json 三个文件 缺一不可(注&#x…

Transformer预测 | 基于Transformer的锂电池寿命预测(Pytorch,CALCE数据集)

文章目录 文章概述模型描述程序设计参考资料文章概述 Pytorch实现基于Transformer 的锂电池寿命预测,环境为pytorch 1.8.0,pandas 0.24.2 随着充放电次数的增加,锂电池的性能逐渐下降。电池的性能可以用容量来表示,故寿命预测 (RUL) 可以定义如下: SOH(t)=CtC0100%, 其中,…

JQuery 概念、历史、发展、优势-JQuery开发教程

一、JQuery 框架简介 jQuery 是一个 轻量级 JavaScript 库。 jQuery 极大地简化了 JavaScript 编程。 jQuery 很容易学习。 jQuery是一个快速、简洁的JavaScript框架,是继Prototype之后又一个优秀的JavaScript代码库(框架)于2006年1月由Joh…

@NotBlank、@NotNull、@NotEmpty、@NonNull四者之间的区别

文章目录 NotNullNotEmptyNotBlankNonNull NotNull 1.NotNull:用在基本类型上,不能为null,但可以为空字符串 NotEmpty 2.NotEmpty:用在集合类上,不能为null,并且长度必须大于0 NotBlank 3.NotBlank&am…

HarmonyOS Next 系列之可移动悬浮按钮实现(六)

系列文章目录 HarmonyOS Next 系列之省市区弹窗选择器实现(一) HarmonyOS Next 系列之验证码输入组件实现(二) HarmonyOS Next 系列之底部标签栏TabBar实现(三) HarmonyOS Next 系列之HTTP请求封装和Token…

ios swift5 播放视频失败 本地的可以 网页链接播放失败

Main thread blocked by synchronous property query on not-yet-loaded property (PreferredTransform) for HTTP(S) asset. This could have been a problem if this asset were being read from a slow network. Asset is not playable

基数排序!

大鸡排~ 算法描述定义常量和全局变量初始化PowOfBase数组输入函数和输出函数获取某一位的基数值基数排序函数主函数 完整代码 https://articles.zsxq.com/id_flaketn5n3uo.html 算法描述 定义常量和全局变量 const int MAXN 100005; // 1 const int MAXT …

MQ~消息队列能力、AMQP协议、现有选择(Kafka、RabbitMQ、RocketMQ 、Pulsar)

消息队列 消息队列看作是一个存放消息的容器,当我们需要使用消息的时候,直接从容器中取出消息供自己使用即可。由于队列 Queue 是一种先进先出的数据结构,所以消费消息时也是按照顺序来消费的。 常⽤的消息队列主要这 五 种,分别…

使用 DISPATCHERS 进行 Blueprint 之间的通信

文章目录 初始准备DISPATCHERS 的创建和绑定实现效果 初始准备 首先 UE5 默认是不提供 静态网格体编辑器也就是 Modeling Mode 的,这里需要从插件中添加 Modeling Tools Editor Mode 进入 Modeling Mode 模式,创建一个正方体 然后利用 PolyGroup Edit 和…

网络编程1

网络编程中&#xff0c;客户端调用close或者shutdown后&#xff0c;操作系统会给服务器发送一个FIN #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h>int main() {int sockfd;struct s…

Vue79-路由组件独有的2个新的生命周期钩子

一、需求 news.vue路由组件被缓存了&#xff08;因为想要保留里面的输入框的数据&#xff01;&#xff09;&#xff0c;导致&#xff0c;路由页面切走&#xff0c;组件也不会被销毁&#xff0c;所以&#xff0c;beforeDestroy()函数就不会被执行&#xff0c;所以&#xff0c;定…

npm、yarn、pnpm 最新国内镜像源设置和常见问题解决

1. npm 设置国内镜像源 1.1 镜像源概述 镜像源是软件包管理工具用来下载和安装软件包的服务器地址。由于网络原因&#xff0c;直接使用官方源可能会导致速度慢或连接失败的问题。国内镜像源可以提供更快的访问速度和更稳定的连接。 1.2 镜像源的选择 国内有许多可用的npm镜…

Java中如何使用设计模式来解决编程问题?

Java中使用设计模式来解决编程问题&#xff0c;可以显著提高代码的可复用性、可维护性和可读性。设计模式是一套被广泛应用于软件工程的解决方案&#xff0c;描述了在特定上下文中面对具体问题时的可复用解决方案。以下是几种常用的设计模式及其应用场景&#xff1a; 单例模式…

数据结构课设——文章编辑系统

需求分析(菜单 输入文章 统计字符 童子字符串出现次数 删除某子串 查看文章 保存文章 加载文章)、概要设计(算法功能设计 软件环境)、详细设计(主要数据类型 变量 函数 算法流程图)、调试分析(非法合法测试数据、遇到问题解决方案解决结果)、总结、文献、附录(代码) …

React+TS前台项目实战(十二)-- 全局常用组件Toast封装,以及rxjs和useReducer的使用

文章目录 前言Toast组件1. 功能分析2. 代码详细注释&#xff08;1&#xff09;建立一个reducer.ts文件&#xff0c;用于管理状态数据&#xff08;2&#xff09;自定义一个清除定时器的hook&#xff08;3&#xff09;使用rxjs封装全局变量管理hook&#xff08;4&#xff09;在to…

文字模拟:经营酒店隐私政策

隐私政策 文字模拟&#xff1a;经营酒店隐私政策 一、引言 本隐私政策适用于我们提供的文字模拟&#xff1a;经营酒店小游戏&#xff08;以下简称“游戏”&#xff09;。我们非常重视用户的隐私和个人信息的保护&#xff0c;因此制定了本隐私政策&#xff0c;以解释我们如何…

在scrapy中使用Selector提取数据

经院吉吉&#xff1a; 首先说明一下&#xff0c;在scrapy中使用选择器是基于Selector这个对象滴&#xff0c;selector对象在scrapy中通过XPATH或是CSS来提取数据的&#xff0c;我们可以自己创建selector对象&#xff0c;但在实际开发中我们不需要这样做&#xff0c;因为respons…

御道源码(ruoyi-vue-pro)个人使用小结

御道源码&#xff08;ruoyi-vue-pro&#xff09;个人使用小结 一、Git地址 1、平台项目简介及地址 2、开发指南&#xff0c;如图所示&#xff0c;部分功能需要收费&#xff0c;可自行了解 二、项目文件夹结构示例&#xff1a; 三、技术介绍 1.基于 Spring Boot MyBatis P…

Java字符串连接符拼接操作

在Java的算术运算符中的加法符号“ ”&#xff0c;可以用来进行算术运算&#xff0c;也可以用来当作连接符进行字符串的拼接。 当“ ”操作中出现字符串时&#xff0c;这个“ ”是字符串连接符&#xff0c;而不是运算符了。 会将前后的数据进行拼接在一起&#xff0c;并产生…