From 4abad6851f627b9c0826328057b20f10030fcf41 Mon Sep 17 00:00:00 2001 From: zj3D Date: Fri, 7 Mar 2025 12:32:22 +0800 Subject: [PATCH] 02 --- B 高性能模式/01 高性能模式.md | 24 ++++---- .../02 操作系统相关知识.md | 15 +++-- .../03 多线程的应用场景.md | 55 +++---------------- B 高性能模式/04 其它知识.md | 1 + 4 files changed, 29 insertions(+), 66 deletions(-) diff --git a/B 高性能模式/01 高性能模式.md b/B 高性能模式/01 高性能模式.md index 794db70..d9eea22 100644 --- a/B 高性能模式/01 高性能模式.md +++ b/B 高性能模式/01 高性能模式.md @@ -2,7 +2,7 @@ 从计算机系统结构的角度,提高 Python 任务执行速度的核心在于:减少解释器开销(编译/JIT)、提升并行性(多核/GPU)、优化内存访问(缓存友好)、降低 I/O 瓶颈以及适配硬件特性等。当前主要办法如下: ### 计算单元层面利用多核并行计算 -对于 CPU 密集型任务,使用多进程,每个进程拥有独立的 Python 解释器和内存空间运行在独立的内核上,实现并行计算。 +对于 CPU 密集型任务,使用多进程,每个进程拥有独立的 Python 解释器和内存空间,运行在独立的内核上,实现并行计算。 ### I/O 层面减少等待时间 @@ -12,30 +12,30 @@ ### 编译层面减少解释器开销 -- 使用 JIT 编译器:Just-In-Time(JIT)编译可以在运行时将Python代码编译成机器码,从而提升执行速度 。PyPy 是一种替代 CPython 的实现,使用 JIT 技术,PyPy 的 JIT 引擎可以分析代码执行路径,优化频繁调用的函数,充分利用处理器架构。 -- **Cython 编译**:Cython 允许开发者为 Python 代码添加 C 类型的注解,并编译为 C 代码,再由 C 编译器生成机器码。Cython 特别适合静态类型优化的场景。 +- 使用 JIT 编译器:Just-In-Time(JIT)编译可以在运行时将Python代码编译成机器码,从而提升执行速度 。PyPy 是一种替代 CPython 的实现,PyPy 的 JIT 引擎可以分析代码执行路径,优化频繁调用的函数,充分利用处理器架构。 +- **Cython 编译**:Cython 允许开发者为 Python 代码添加 C 类型注解,并编译为 C 代码,再由 C 编译器生成机器码。Cython 特别适合静态类型优化场景。 ### 利用Python的解释器特性 - **使用内置数据类型和函数**:内置的数据类型(如列表、字典、集合等)和函数通常经过高度优化。 -- **选择合适的数据结构**:例如,一些类型执行一些操作更快,一些类型更省空间 +- **选择合适的数据结构**:例如,一些类型执行一些操作更快,一些类型更省空间。 - **减少全局变量的使用**:访问全局变量通常比局部变量慢,因为它们需要在更大的作用域中查找。 - **减少函数调用**,可降低堆栈操作开销。 -- 使用列表推导式替代循环追加,避免频繁创建和销毁临时对象的开销。 +- 使用列表推导式替代循环,降低频繁创建和销毁临时对象的开销。 - 使用生成器而不是列表来处理大数据集,以减少内存占用。 - 使用XX池或预分配资源。 ### 使用第三方高性能库 - NumPy、Pandas这些库用 C/C++ 编写并经过优化。 -- NumPy 使用连续内存块存储数据,向量化操作来代替显式的Python循环更高效 。 -- SIMD 指令加速,NumPy、Numba、Pandas/SciPy 都使用了SIMD。Cython 可以直接用 C 代码使用SIMD 。 +- NumPy 使用连续内存块存储数据,向量化操作来代替显式的Python循环,更高效 。 +- SIMD 指令加速,NumPy、Numba、Pandas/SciPy 都使用了 SIMD。Cython 可以直接用 C 代码使用 SIMD 。 - `gzip` 模块可压缩数据,减少网络传输的数据量,提高网络传输速度。 -- `mmap` 模块进行内存映射文件,处理超大文件、优化I/O性能以及进程间通信方面具有显著优势。 -- `functools.lru_cache` 缓存计算结果,避免重复计算 。 +- `mmap` 模块实现内存映射文件,在处理超大文件、优化I/O性能以及进程间通信方面具有显著优势。 +- `functools.lru_cache` 缓存计算结果,避免重复计算 。 ## 总结 -具体实施时,应根据任务类型(CPU 密集型、I/O 密集型或混合型)选择合适的优化策略,并结合性能分析工具(如 cProfile 、timeit或 line_profiler)定位瓶颈。 -计算设备方面的简单提升办法:使用多机、更快的 CPU、更多核的CPU、更多的内存、更快的存储、使用 GPU/FPGA/TPU 。 -此外,随着Python社区的发展,新的技术和工具不断涌现,开发者应持续关注最新的进展,以便更好地优化自己的代 。 \ No newline at end of file +具体实施时,应根据任务特点选择合适的策略,并结合性能分析工具(如 cProfile 、timeit或 line_profiler)定位瓶颈。 +计算设备方面的简单提升办法:使用多机、更快的 CPU、更多核的CPU、更多的内存、更快的存储、增加 GPU/FPGA/TPU 。 +此外,随着Python社区的发展,新的技术和工具不断涌现,开发者应持续关注最新进展,以便更好地优化自己的代码 。 \ No newline at end of file diff --git a/B 高性能模式/02 操作系统相关知识.md b/B 高性能模式/02 操作系统相关知识.md index 4c04d9b..32667b2 100644 --- a/B 高性能模式/02 操作系统相关知识.md +++ b/B 高性能模式/02 操作系统相关知识.md @@ -1,27 +1,30 @@ ### 内存管理 -段:存放的是全局变量和静态变量 +段:存放全局变量和静态变量 栈:系统自动分配释放,函数参数值,局部变量,返回地址等在此 堆:存放动态分配的数据,由开发人员自行管理 不同操作系统进程和线程实现机制有不同。 虚拟内存技术,把进程虚拟地址空间划分成用户空间和内核空间。 -在 32 位的操作系统中,4GB 的进程地址中用户空间为 0~3G,内核地址空间为 3~4G, +在 32 位操作系统中,4GB 的进程地址中用户空间为 0~3G,内核地址空间为 3~4G, 用户不能直接操作内核地址,只有通过系统调用的方式访问。 线程共享虚拟内存和全局变量等资源,线程拥有自己的私有数据比如栈和寄存器。 ## 多任务 -多任务就是操作系统可以同时运行多个任务。分为并行和并发两种。 +多任务就是可以同时运行多个任务。分为并行和并发两种。 并行是真在不同CPU核上同时执行,并发是轮换在一个核上执行。 + ## 阻塞/非阻塞 等候消息的过程中能不能干其他事 + ## 同步/异步 -指的是消息通知的机制 +一个任务完成后才能开始下一个任务是同步, +多个任务同时在运行状态是异步 。 通知调用者的三种方式,如下 状态:即监听被调用者的状态,调用者每隔一段时间检查一次是否完成(轮询)。 通知:当被调用者执行完成后,发出通知告知调用者。 @@ -42,7 +45,7 @@ 一个进程无法访问另一个进程的空间 一个进程运行的失败也不会影响其他进程的运行 -因为操作系统可以切换进程,所以看起来同时运行的进程数会超过核数 +因为操作系统可以切换进程,所以并发的进程数会超过核数 当需要创建的子进程数量巨大时,可以创建进程池 进程间常通过消息队列程序实现数据传递 @@ -53,6 +56,6 @@ 一个进程下的多个线程可以共享该进程的资源,包括内存。 多个线程同时对同一个全局变量操作,会出现竞争问题,从而数据结果会不正确 -同步控制。某个线程要更改数据时,先将其锁定,直到将状态变成“非锁定”,其他的线程才能锁该资源。 +解决办法:某个线程要更改数据时,先将其锁定,直到将状态变成“非锁定”,其他的线程才能锁该资源。 如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。 可以用一些机制解决死锁,比如超时。 \ No newline at end of file diff --git a/B 高性能模式/03 多线程的应用场景.md b/B 高性能模式/03 多线程的应用场景.md index 112fc01..76343ca 100644 --- a/B 高性能模式/03 多线程的应用场景.md +++ b/B 高性能模式/03 多线程的应用场景.md @@ -1,19 +1,17 @@ Python的多线程时间切片间隔可以通过 sys.setswitchinterval() 设置。其他切换触发条件 : -- 当线程等待I/O操作(如网络请求或磁盘读写)时,GIL会被释放,允许其他线程运行。 -- 某些函数(如 time.sleep())会显式释放GIL,切换到其他线程执行。 -- 线程主动释放GIL。 +- 当线程等待I/O操作(如网络请求或磁盘读写) +- 某些函数(如 time.sleep())会触发切换 +- 线程主动释放GIL -异步编程特别适合高并发的 I/O 密集型任务(如 Web 服务器、爬虫、实时通信), 特别是大量并发连接的任务。 -对于 **I/O 密集型任务**,**异步编程** 通常比 **多线程** 是更好的选择。 -多线程相对编程简单 。 +异步编程通常比多线程控制更精细,但,多线程相对编程简单 。 以下场景更适合使用 **多线程**: ### 场景:**GUI 应用程序** -在 GUI(图形用户界面)应用程序中,主线程负责处理用户交互,而其他任务(如文件读写、网络请求)需要在后台运行,以避免阻塞主线程导致界面卡顿。多线程可以与 GUI 主线程共享内存,方便更新界面状态。线程间通信简单,适合处理后台任务。GUI 框架(如 PyQt、Tkinter)通常有自己的事件循环,与异步编程的事件循环冲突。 +在 GUI(图形用户界面)应用程序中,主线程负责处理用户交互,而其他任务(如文件读写、网络请求)需要在后台运行,以避免阻塞主线程导致界面卡顿。多线程可以与 GUI 主线程共享内存,方便更新界面状态。线程间通信简单。GUI 框架(如 PyQt、Tkinter)通常有自己的事件循环,用异步编程容易冲突。 ```python @@ -134,8 +132,8 @@ main() ### 场景:**任务队列与线程池** -在需要处理大量短期任务的场景中(如 Web 服务器的请求处理),使用线程池可以简单编程实现高效地管理任务。 -特别类似上面场景,有些任务是阻塞式的,不支持异步 +在需要处理大量短期任务的场景中(如 Web 服务器的请求处理),使用线程池可以简单编程实现高效管理任务。 +特别有些任务是阻塞式的,不支持异步 。 ```python import concurrent.futures @@ -186,42 +184,3 @@ def main(): 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 高性能模式/04 其它知识.md b/B 高性能模式/04 其它知识.md index c36aeb7..7a3d01a 100644 --- a/B 高性能模式/04 其它知识.md +++ b/B 高性能模式/04 其它知识.md @@ -18,6 +18,7 @@ JIT 的工作原理:**解释执行**:程序开始时,代码以解释方式 异步编程:异步编程是一种编程范式,允许任务并发执行。 在 Python 中,异步编程可以通过协程、回调、事件循环等多种方式实现。 +异步编程适合高并发的 I/O 密集型任务(如 Web 服务器、爬虫、实时通信), 特别是大量并发连接的任务。 协程:协程是异步编程的一种实现方式,协程是一种在执行过程中可以暂停和恢复的函数。 协程运行在线程之上,协程的调度完全由用户控制 。