Python性能优化:实战技巧与最佳实践

news2024/10/3 13:54:07

Python性能优化:实战技巧与最佳实践

Python 作为一种动态解释型语言,虽然以其简洁和易用性闻名,但在性能方面可能不如静态编译型语言如 C++ 和 Java 高效。为了在高性能要求的应用场景下更好地利用 Python,我们需要掌握一些常见的优化技巧和最佳实践。

本文将介绍如何通过以下几种方法优化 Python 程序的性能,并附上相应的代码示例:

  • 优化算法和数据结构
  • 使用合适的内置函数和库
  • 减少不必要的计算
  • 并行化与多线程/多进程
  • 使用 JIT 编译器加速
  • 内存管理优化
  • 利用C扩展模块提升性能
  • 延迟计算与懒惰求值
  • 优化 I/O 操作
  • 使用合适的数据序列化格式

在这里插入图片描述

1. 优化算法和数据结构

Python 的性能很大程度上取决于你所使用的算法和数据结构。选择合适的数据结构和算法可以显著提高代码效率。

示例:

在处理大量数据时,选择合适的数据结构尤为重要。比如,如果频繁查找元素,使用 setlist 更有效率。

# 使用列表
items = [i for i in range(10000)]
if 9999 in items:  # O(n) 复杂度
    print("Found")

# 使用集合
items_set = {i for i in range(10000)}
if 9999 in items_set:  # O(1) 复杂度
    print("Found")

在上述例子中,set 的查找时间复杂度为 O(1),而 list 为 O(n),在大数据量下性能差异显著。
在这里插入图片描述

2. 使用合适的内置函数和库

Python 提供了很多高效的内置函数和库,善用它们可以避免手动编写复杂的逻辑,提高性能。

例如,使用 sum() 比手动编写循环更高效。

示例:

# 手动求和
def manual_sum(nums):
    total = 0
    for num in nums:
        total += num
    return total

# 使用内置sum函数
nums = list(range(1000000))
print(manual_sum(nums))  # 手动求和
print(sum(nums))  # 内置函数求和

sum() 函数是用 C 实现的,比手动实现的 Python 循环更高效。
在这里插入图片描述

3. 减少不必要的计算

避免重复计算可以显著减少运行时间,尤其是当相同的值多次使用时。可以通过缓存中间结果或使用记忆化来实现。

示例:

在递归中,通过缓存计算过的结果来避免重复计算:

# 使用记忆化优化斐波那契数列计算
from functools import lru_cache

@lru_cache(maxsize=None)
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

print(fib(40))

这里使用了 functools.lru_cache 装饰器,缓存之前计算的结果,避免了重复计算。对于递归计算,性能提升显著。
在这里插入图片描述

4. 并行化与多线程/多进程

Python 的全局解释器锁(GIL)在某些场景下限制了多线程的并发性能,但对于 I/O 密集型任务,多线程仍然可以提高性能。对于 CPU 密集型任务,多进程可以更好地发挥并行处理能力。

示例:

使用 concurrent.futures 模块并行化任务:

import concurrent.futures
import time

def task(n):
    time.sleep(n)
    return n

# 使用线程池
start_time = time.time()
with concurrent.futures.ThreadPoolExecutor() as executor:
    results = list(executor.map(task, [2, 3, 4]))

print(f"Threaded tasks completed in: {time.time() - start_time:.2f} seconds")

# 使用进程池
start_time = time.time()
with concurrent.futures.ProcessPoolExecutor() as executor:
    results = list(executor.map(task, [2, 3, 4]))

print(f"Process-based tasks completed in: {time.time() - start_time:.2f} seconds")

对于 I/O 密集型任务,多线程可以带来性能提升;而对于 CPU 密集型任务,使用多进程则效果更佳。
在这里插入图片描述

5. 使用 JIT 编译器加速

Just-in-Time(JIT)编译器如 PyPy 可以将 Python 字节码动态编译为机器代码,从而提升执行速度。PyPy 通常比标准 CPython 快,特别是对于长时间运行的程序。

示例:

使用 PyPy 运行相同的 Python 代码,一般会有 2-3 倍的速度提升。

# 使用 PyPy 运行代码
pypy my_script.py

对于 CPU 密集型任务,PyPy 的优势尤为明显。不过 PyPy 并不完全兼容所有的 Python 库,尤其是一些 C 扩展库。
在这里插入图片描述

6. 内存管理优化

Python 的内存管理基于引用计数和垃圾回收。为了减少不必要的内存占用,可以通过以下方式进行优化:

  • 避免循环引用:Python 的垃圾回收器能够处理循环引用,但减少循环引用有助于降低 GC 的负担。
  • 生成器替代列表:生成器在需要大量数据时,避免了一次性将数据加载到内存中的问题。

示例:

使用生成器替代列表可以显著减少内存占用:

# 使用列表(占用大量内存)
large_list = [i for i in range(1000000)]

# 使用生成器(惰性求值,减少内存占用)
large_generator = (i for i in range(1000000))

print(sum(large_list))  # 列表求和
print(sum(large_generator))  # 生成器求和

生成器在每次迭代时才生成下一个元素,这使得它比列表占用更少的内存,特别适合处理大数据集。


在这里插入图片描述

7. 利用C扩展模块提升性能

Python 通过 C 扩展模块可以将性能敏感的部分代码用 C 或 C++ 编写,以获得接近原生语言的性能。常用的 C 扩展模块包括 Cythonctypes

  • Cython 是一种 Python 的超集语言,可以将 Python 代码编译为 C,极大地提升性能。
  • ctypes 允许调用 C 库函数,可以在需要高性能的部分借助已有的 C 库。

示例:

使用 Cython 将 Python 函数加速:

首先安装 Cython:

pip install cython

然后,创建一个 .pyx 文件,将其中的代码编译为 C 执行:

# file: fib.pyx
def fib_cython(int n):
    if n < 2:
        return n
    return fib_cython(n - 1) + fib_cython(n - 2)

编译该代码:

cythonize -i fib.pyx

之后你可以在 Python 中直接调用 Cython 编译的函数,获得显著的性能提升:

import fib
print(fib.fib_cython(40))

相比原生 Python 实现,Cython 可以在计算密集型任务中提升数倍甚至数十倍的性能。
在这里插入图片描述

8. 延迟计算与懒惰求值

在某些场景下,推迟或避免不必要的计算可以提高性能。Python 提供了诸如生成器、itertools 模块和 functoolslazy 计算机制,用来减少资源消耗。

示例:

通过使用 itertools.islice() 实现懒惰求值,仅在需要时计算部分结果:

import itertools

# 创建一个无限迭代器
infinite_iter = itertools.count()

# 只获取前10个元素
limited_iter = itertools.islice(infinite_iter, 10)

for num in limited_iter:
    print(num)

在这种情况下,itertools.islice() 只会计算所需的元素,而不是生成整个无限序列。对于大数据集或流数据处理,懒惰求值能够显著提高性能。
在这里插入图片描述

9. 优化 I/O 操作

在 I/O 密集型任务中,读取和写入文件、网络请求等往往是性能瓶颈。以下是一些常见的 I/O 优化策略:

  • 批量处理 I/O 操作:减少频繁的 I/O 操作,通过将多个操作批量处理来提高效率。
  • 异步 I/O:使用 asyncio 或第三方库(如 aiohttp)进行异步 I/O 操作,避免阻塞,提高响应速度。

示例:

使用 asyncio 执行异步 I/O 操作:

import asyncio
import aiohttp

async def fetch_url(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

async def main():
    urls = ['https://www.example.com', 'https://www.python.org']
    tasks = [fetch_url(url) for url in urls]
    results = await asyncio.gather(*tasks)
    for result in results:
        print(result[:100])  # 打印前100个字符

asyncio.run(main())

相比于同步 I/O,异步 I/O 能够在等待网络或文件 I/O 时进行其他操作,从而提升效率。
在这里插入图片描述

10. 使用合适的数据序列化格式

在处理大量数据时,选择合适的序列化格式可以显著提升性能。常见的序列化格式包括:

  • JSON:通用格式,但解析速度较慢,适用于跨语言数据交换。
  • MessagePack:比 JSON 更紧凑和高效的二进制格式。
  • Protocol Buffers:Google 的高效序列化方案,适合大型数据和高频序列化需求。

示例:

使用 MessagePack 替代 JSON 进行序列化和反序列化:

import json
import msgpack
import time

data = {'key': 'value', 'numbers': list(range(1000))}

# 使用JSON
start_time = time.time()
json_data = json.dumps(data)
loaded_json = json.loads(json_data)
print(f"JSON Serialization Time: {time.time() - start_time:.6f} seconds")

# 使用MessagePack
start_time = time.time()
msgpack_data = msgpack.packb(data)
loaded_msgpack = msgpack.unpackb(msgpack_data)
print(f"MessagePack Serialization Time: {time.time() - start_time:.6f} seconds")

相比 JSON,MessagePack 更紧凑,序列化和反序列化的速度更快,适合高性能场景。


在这里插入图片描述

总结

Python 性能优化并非单一的技巧,而是多种策略的组合。通过选择合适的数据结构、减少不必要的计算、利用多线程和多进程、使用 C 扩展模块以及高效的 I/O 和序列化操作,可以显著提升 Python 程序的运行效率。

在应用这些优化技巧时,应该注意以下几点:

  • 根据实际场景选择优化手段:不同的优化技术适用于不同类型的程序,盲目优化可能适得其反。
  • 保持代码的可维护性:性能优化不能牺牲代码的可读性和可维护性,务必在两者之间取得平衡。
  • 测量和调试:使用 timeitcProfile 等工具对代码进行性能测试,找到瓶颈后再进行针对性的优化。

通过不断实践和优化,开发者可以在 Python 中实现既高效又易维护的应用程序。
在这里插入图片描述

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

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

相关文章

STM32GPIO输入和输出

一、先看IO端口位的结构 上面部分是输入&#xff0c;下面是输出。 1、I/O输入&#xff1a; 首先&#xff0c;从I/O引脚开始&#xff0c;有两个保护二极管&#xff0c;主要作用是对输入电压限幅&#xff0c;保护内部电路。上面二极管接VDD为3.3V,下面二极管接VSS为0V。当输入电…

认知杂谈71《创业抉择:定制化与标准化的权衡之路》

内容摘要&#xff1a; *嘿&#xff0c;彦祖们&#xff01;今天来聊聊创业的事&#xff0c;创业选产品类型很关键。定制化产品如魔法&#xff0c;贴合客户需求但成本高且有边际递减风险。要掌握物联网技术&#xff0c;用 3D 建模软件&#xff0c;参考特定书籍&#xff0c;参加展…

在线JSON可视化工具--支持缩放

先前文章提到的超好用的JSON可视化工具&#xff0c;收到反馈&#xff0c;觉得工具好用&#xff0c;唯一不足就是不能缩放视图&#xff0c;其实是支持的&#xff0c;因为滚轮有可能是往下滚动&#xff0c;会与缩放冲突&#xff0c;所以这个工具设计为需要双击视图来触发打开缩放…

C++ 线性表、内存操作、 迭代器,数据与算法分离。

线性表&#xff1a; 线性表是最基本、最简单、也是最常用的一种数据结构。线性表&#xff08;linear list&#xff09;是数据结构的 一种&#xff0c;一个线性表是n个具有相同特性的数据元素的有限序列。 线性表中数据元素之间的关系是一对一的关系&#xff0c;即除了第一个和…

Ubuntu2404安装

Ubuntu是一款非常优秀的发行版本&#xff0c;起初她的优势主要在于桌面版&#xff0c;但是随着Centos 从服务版的支持的退出&#xff0c;Ubuntu server也在迅猛的成长&#xff0c;并且不断收获了用户&#xff0c;拥有了一大批忠实的粉丝。好了&#xff0c;废话不多说&#xff0…

基于SSM的出租车租赁管理系统的设计与实现

文未可获取一份本项目的java源码和数据库参考。 1 选题的背景 现代社会&#xff0c;许多个人、家庭&#xff0c;因为生活、工作方式的改变&#xff0c;对汽车不再希望长期拥有&#xff0c;取而代之的是希望汽车能“召之即…

CSS 实现楼梯与小球动画

CSS 实现楼梯与小球动画 效果展示 CSS 知识点 CSS动画使用transform属性使用 页面整体布局 <div class"window"><div class"stair"><span style"--i: 1"></span><span style"--i: 2"></span>…

Flask-3

文章目录 ORMFlask-SQLAlchemySQLAlchemy中的session对象数据库连接设置常用的SQLAlchemy字段类型常用的SQLAlchemy列约束选项 数据库基本操作模型类定义 数据表操作创建和删除表 数据操作基本查询SQLAlchemy常用的查询过滤器SQLAlchemy常用的查询结果方法多条件查询分页器聚合…

Rstudio:强大的R语言集成开发环境(IDE)

Rstudio 应该是 R 语言使用的标配&#xff0c;尽管 Rstudio 的母公司 Posit 推出了新一代的集成开发环境 Positron&#xff0c;但其还处于开发阶段。作为用户不妨让其成熟后再使用&#xff0c;现阶段还是 Rstudio 更稳定。 如果你在生物信息学或统计学领域工作&#xff0c;R语言…

C初阶(六)--- static 来喽

前言&#xff1a;C语言中有许多关键字&#xff08;关键字是预先保留的标识符&#xff0c;具有特殊意义&#xff0c;不能用作变量 名、函数名等普通标识符。&#xff09; 比如&#xff1a;前面在变量与常量那一节提到的extern 就是一个关键字&#xff0c;应该还记得e…

开源项目 - 交通工具检测 yolo v3 物体检测 单车检测 车辆检测 飞机检测 火车检测 船只检测

开源项目 - 交通工具检测 yolo v3 物体检测 单车检测 车辆检测 飞机检测 火车检测 船只检测 开源项目地址&#xff1a;https://gitcode.net/EricLee/yolo_v3 示例&#xff1a;

点云补全 学习笔记

目录 Depth completion with convolutions and vision transformers 依赖项&#xff1a; DCNv2 softpoolnet Depth completion with convolutions and vision transformers Zhang, Y., Guo, X., Poggi, M., Zhu, Z., Huang, G., Mattoccia, S.: Completionformer: Depth co…

JS进阶 3——深入面向对象、原型

JS 进阶3——深入面向对象、原型 1.编程思想 面向过程&#xff1a;分析出解决问题的过程&#xff0c;然后用函数将这些步骤一步步封装起来面向对象&#xff1a;将事物分为一个个对象&#xff0c;然后对象之间分工合作 2.构造函数&#xff1a;封装性、面向对象 构造函数方法存…

Python画笔案例-074 绘制轮子走了

1、绘制轮子走了 通过 python 的turtle 库绘制 轮子走了,如下图: 2、实现代码 绘制轮子走了,以下为实现代码: """轮子走了.py """ import time import turtle def draw_polygon(number,length):

Spark读取MySQL优化方案辩证

0、背景 上篇文章《Spark 任务需要的内存跟哪些因素有关》验证 Spark 任务需要的内存&#xff0c;跟单个 partition 的数据量大小&#xff0c;以及数据计算逻辑复杂度有关。但是之中有个最大的特点&#xff0c;就是把 MySQL 作为数据源的时候&#xff0c;无论数据量多大&#…

【C++】set容器和map容器的基本使用

一、序列式容器和关联式容器 1、STL中的部分容器如&#xff1a;string、vector、list、deque、array、forward_list等&#xff0c;这些容器统称为序列式容器&#xff0c;因为逻辑结构为线性序列的数据结构&#xff0c;两个位置存储的值之间一般没有紧密的关联关系&#xff0c;…

数据结构双向链表和循环链表

目录 一、循环链表二、双向链表三、循环双向链表 一、循环链表 循环链表就是首尾相接的的链表&#xff0c;就是尾节点的指针域指向头节点使整个链表形成一个循环&#xff0c;这就弥补了以前单链表无法在后面某个节点找到前面的节点&#xff0c;可以从任意一个节点找到目标节点…

Leetcode 540. 有序数组中的单一元素

1.题目基本信息 1.1.题目描述 给你一个仅由整数组成的有序数组&#xff0c;其中每个元素都会出现两次&#xff0c;唯有一个数只会出现一次。 请你找出并返回只出现一次的那个数。 你设计的解决方案必须满足 O(log n) 时间复杂度和 O(1) 空间复杂度。 1.2.题目地址 https:…

大语言模型入门(二)——提示词

一、什么是提示词 大语言模型&#xff08;LLM&#xff09;的提示词&#xff08;Prompt&#xff09;是与模型交互的关键&#xff0c;它影响着模型的输出结果。提示词&#xff08;Prompt&#xff09;和提示工程&#xff08;Prompt Engineering&#xff09;密切相关。什么又是提示…

详解代理服务器及Squid

一、 代理服务器简介 &#xff08;1&#xff09;什么是代理服务器 代理服务器英文全称为ProxyServer&#xff0c;其主要功能代理网络用户获取网络信息&#xff0c;起到内网和Internet的桥梁作用。 在TCP/IP网络中&#xff0c;传统的通信过程是这样的&#xff1a;客户端向服务…