diff --git a/B 高性能模式/01 高性能模式.md b/B 高性能模式/01 高性能模式.md new file mode 100644 index 0000000..ab2d1a4 --- /dev/null +++ b/B 高性能模式/01 高性能模式.md @@ -0,0 +1,48 @@ + + +本文从计算机系统结构的角度探讨提高 Python 代码任务执行速度的方法,涵盖硬件与软件交互的优化策略。以下是一些关键方法: + + +计算单元层面利用多核并行计算 +- 对于 CPU 密集型任务,使用多进程,每个进程拥有独立的 Python 解释器和内存空间运行在独立的内核上,实现并行计算。 + + + I/O 层面减少等待时间 +- 异步编程:asyncio 库允许在单线程中处理多个 I/O 操作(实现并发执行),减少等待时间。 +- 多线程:Python的线程切换是由解释器完成,而不是操作系统。切换不仅基于时间间隔,Python的多线程 时间切片间隔可以通过 sys.setswitchinterval() 设置,通常以秒为单位。其他切换触发条件 : + - 当线程等待I/O操作(如网络请求或磁盘读写)时,GIL会被释放,允许其他线程运行。 + - 某些函数(如 time.sleep())会显式释放GIL。 + - 线程主动释放GIL。 +- 批量处理,减少I/O请求数量 + + +编译层面减少解释器开销 +- 使用 JIT 编译器:Just-In-Time(JIT)编译可以在运行时将Python代码编译成机器码,从而提升执行速度 。PyPy 是一种替代 CPython 的 Python 实现,使用即时编译(JIT)技术,PyPy 的 JIT 引擎可以分析代码执行路径,优化频繁调用的函数,充分利用处理器架构。 +- **Cython 编译**:Cython 允许开发者为 Python 代码添加 C 类型的注解,并编译为 C 代码,再由 C 编译器生成机器码。Cython 可实现接近 C 的执行速度,特别适合静态类型优化的场景。 + + + 利用Python的语言特性 +- **使用内置数据类型和函数**:内置的数据类型(如列表、字典、集合等)和函数通常经过高度优化。 +- **减少全局变量的使用**:访问全局变量通常比局部变量慢,因为它们需要在更大的作用域中查找。 +- 减少函数调用可降低堆栈操作开销 +- **选择合适的数据结构**:例如,如果需要快速查找元素,则应该优先考虑使用字典或集合而非列表 +- 使用列表推导式替代循环追加,避免频繁创建和销毁临时对象的开销。 +- 使用生成器而不是列表来处理大数据集,以减少内存占用。 +- 使用XX池或预分配资源。 + + +使用第三方高性能库 +- NumPy、Pandas这些库通常用 C/C++ 编写并经过优化。 +- NumPy 模块使用连续内存块存储数据,向量化操作来代替显式的Python循环更高效 。 +- SIMD 指令加速, NumPy、Numba、Pandas/SciPy 都使用了SIMD。Cython 可以直接用 C 代码使用SIMD 。 +- `gzip` 模块可压缩数据,减少网络传输的数据量,提高网络传输速度。 +- `mmap` 模块进行内存映射文件,处理超大文件、优化I/O性能以及实现高效的进程间通信方面具有显著优势。 +- `functools.lru_cache` 缓存计算结果,避免重复计算 。 + + +#### 讨论 + +从计算机系统结构的角度,提高 Python 代码速度的核心在于:减少解释器开销(编译/JIT)、提升并行性(多核/GPU)、优化内存访问(缓存友好)、降低 I/O 瓶颈以及适配硬件特性。具体实施时,应根据任务类型(CPU 密集型、I/O 密集型或混合型)选择合适的优化策略,并结合性能分析工具(如 cProfile 、timeit或 line_profiler)定位瓶颈。 +计算设备方面提升办法:使用多机、更快的 CPU、更多核的CPU、更多的内存、更快的存储、使用 GPU 、 FPGA 、TPU加速 。 +此外,随着Python社区的发展,新的技术和工具不断涌现,开发者应持续关注最新的进展,以便更好地优化自己的代 。 + diff --git a/B 高性能模式/多线程的应用场景.md b/B 高性能模式/多线程的应用场景.md index 8a1d084..a0960d6 100644 --- a/B 高性能模式/多线程的应用场景.md +++ b/B 高性能模式/多线程的应用场景.md @@ -1,8 +1,10 @@ -对于 **I/O 密集型任务**,**异步编程** 通常比 **多线程** 是更好的选择。异步编程特别适合高并发的 I/O 密集型任务(如 Web 服务器、爬虫、实时通信), 特别是大量并发连接的任务。 +异步编程特别适合高并发的 I/O 密集型任务(如 Web 服务器、爬虫、实时通信), 特别是大量并发连接的任务。 +对于 **I/O 密集型任务**,**异步编程** 通常比 **多线程** 是更好的选择。 +多线程相对编程简单 。 -多线程比相对编程简单 。 +但,以下场景更适合使用 **多线程**: ### 场景:**GUI 应用程序** @@ -92,11 +94,10 @@ if __name__ == "__main__": ``` -以下场景更适合使用 **多线程**: -- -**与阻塞式 API 交互**。 -某些库或 API 是阻塞式的(如某些数据库驱动、硬件接口库),无法直接使用异步编程。在这种情况下,多线程可以避免阻塞主线程。 +### 场景:**与阻塞式 API 交互** +某些库或 API 是阻塞式的(如某些数据库驱动、硬件接口库),无法直接使用异步编程。在这种情况下,多线程可以避免阻塞主线程。 +```python import threading import time import sqlite3 @@ -123,12 +124,99 @@ def main(): print("主线程结束") main() +``` -**实时数据处理**。 在实时数据处理场景中(如音频处理、视频流处理),需要快速响应并处理数据,同时保持主线程的响应性。 +### 场景:**任务队列与线程池** -**任务队列与线程池**。在需要处理大量短期任务的场景中(如 Web 服务器的请求处理),使用线程池可以高效地管理任务。 +在需要处理大量短期任务的场景中(如 Web 服务器的请求处理),使用线程池可以简单编程实现高效地管理任务。 +特别类似上面场景,有些任务是阻塞式的,不支持异步 -**与 C/C++ 扩展交互**。 某些 Python 库是基于 C/C++ 扩展实现的(如 `numpy`、`pandas`),这些扩展可能释放了 GIL,允许在多线程中并行运行。 +```python +import concurrent.futures +import time + +def process_task(task): + print(f"开始处理任务: {task}") + time.sleep(2) # 模拟任务处理时间 + print(f"完成处理任务: {task}") + +def main(): + print("主线程开始") + tasks = ["task1", "task2", "task3", "task4", "task5"] + # 使用线程池处理任务 + with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor: + executor.map(process_task, tasks) + print("主线程结束") -**需要共享状态的场景**。 在某些场景中,多个任务需要频繁共享和修改状态(如缓存、计数器),使用多线程可以方便地共享内存。 +main() +```` + +### 场景:**与 C/C++ 扩展交互** + +某些 Python 库是基于 C/C++ 扩展实现的(如 `numpy`、`pandas`),这些扩展可能释放了 GIL,允许在多线程中并行运行。 +多线程常常更快 。 + +```python +import threading +import numpy as np + +def compute_task(data): + result = np.sum(data) + print(f"计算结果: {result}") + +def main(): + print("主线程开始") + data = np.random.rand(1000000) # 生成随机数据 + # 创建多个线程并行计算 + threads = [] + for i in range(4): + thread = threading.Thread(target=compute_task, args=(data,)) + thread.start() + threads.append(thread) + for thread in threads: + thread.join() + print("主线程结束") + +main() +``` + +### 场景:**需要共享状态** + +在某些场景中,多个任务需要频繁共享和修改状态(如缓存、计数器),使用多线程可以方便地共享内存。 +线程之间可以直接访问和修改共享变量。 +异步任务之间是独立的,不能直接共享变量或状态。 +如果需要在任务之间共享状态,必须通过显式的机制(如队列、回调函数)来传递数据。 + +```python +import threading + +class Counter: + def __init__(self): + self.value = 0 + self.lock = threading.Lock() + + def increment(self): + with self.lock: + self.value += 1 + print(f"计数器值: {self.value}") + +def worker(counter): + for _ in range(5): + counter.increment() + +def main(): + print("主线程开始") + counter = Counter() + # 创建多个线程共享计数器 + threads = [] + for i in range(3): + thread = threading.Thread(target=worker, args=(counter,)) + thread.start() + threads.append(thread) + for thread in threads: + thread.join() + print("主线程结束") + +main() +``` diff --git a/B 高性能模式/相关知识.md b/B 高性能模式/相关知识.md new file mode 100644 index 0000000..34d2da4 --- /dev/null +++ b/B 高性能模式/相关知识.md @@ -0,0 +1,20 @@ + +### 协程 +- 异步编程是一种编程范式,旨在提高程序的并发能力。 +- 协程是异步编程的一种具体实现。协程是一种特殊的函数,可以在执行过程中暂停,并在稍后恢复执行。协程提供了一种轻量级的并发方式,允许多个任务在单线程内交错执行,非常适合 I/O 密集型场景。Python 中的协程通常通过 yield 或 async/await 语法实现: 生成器协程:使用 yield 关键字暂停和恢复执行 ; 原生协程:使用 async def 定义,通过 await 等待其他操作完成。 +- 异步编程在 python 社区讨论中,常常等价于协程,甚至等价于 async + + + +### **JIT(即时编译)** + +JIT(Just-In-Time Compilation,即时编译)是一种在程序运行时将代码编译为机器码的技术。与传统的 **AOT(Ahead-Of-Time Compilation,提前编译)** 不同,JIT 在程序执行过程中动态编译代码,从而结合了解释型语言的灵活性和编译型语言的性能优势。 +JIT 跨平台,生成适合当前平台的机器码。 + +JIT 的工作原理:**解释执行**:程序开始时,代码以解释方式执行(逐行解释字节码)。 **热点检测**:JIT 编译器监控代码执行,识别频繁执行的代码段(称为“热点”)。 **动态编译**:将热点代码编译为机器码,后续执行直接运行机器码,避免解释执行的开销。 **优化**:JIT 编译器可以根据运行时信息进行优化(如内联函数、消除死代码)。 + +在 Python 中利用 JIT 加速的方法包括: +1. **PyPy**:通用的 Python 实现,适合大多数场景。pypy your_script.py +2. **Numba**:专注于数值计算,适合科学计算和数据分析。用 `@jit` 装饰器标记需要加速的函数。 +3. **Cython**:将 Python 代码编译为 C 代码,适合需要极致性能的场景。支持 JIT 和 AOT 编译 。 +4. **Taichi**:专注于高性能计算,适合图形学、物理仿真等领域。 \ No newline at end of file