Python并发入门

2025年3月3日 | 阅读 5 分钟

提高 Python 程序速度的一个显著方法是使用并发。通过同时完成多个操作,并发可以最大限度地利用系统的资源。Python 提供了多种实现并发的方法和模块,包括线程、多进程和异步编程。本文将解释什么是 Python 并发,如何实现它,提供一些出色的示例,并讨论输出。

理解并发编程

它指的是计算机同时处理多个任务的能力。这些任务可以交错执行或在重叠的时间段内执行,但不需要精确地同时完成。处理多个用户输入、管理多个 I/O 操作或处理多个独立任务是并发的主要目标。

什么是并行性?

并发是并行计算的一个子集,并行计算是指任务或进程的同时执行。并行计算的目的是通过同时执行任务来加速计算,而并发则是处理许多任务。提高计算效率和加快系统性能是主要目标。

  • 基于线程的并发:线程会同时创建轻量级的线程,通常称为“工作线程”。这些线程共享相同的内存空间,非常适合 I/O 密集型任务。
  • 基于进程的并发:多进程是指执行多个进程,每个进程都有自己的内存空间。这适用于 CPU 密集型任务,因为它可以使用多个 CPU 核心。
  • 基于协程的并发:异步编程中的“asyncio”、“async”和“await”关键字非常适合高效地控制 I/O 密集型进程。在 I/O 操作期间,它允许任务暂停并将控制权转移给其他任务,而不会导致整个程序崩溃。

并发 vs. 并行

并发:它描述了在重叠的时间段内完成多个活动,但不一定同时进行。它适用于 I/O 密集型进程,并且经常依赖于文件或网络数据等外部资源。

并行:然而,它利用多个 CPU 核心来同时执行多个应用程序。它非常适合涉及大量CPU 功耗的长时处理任务。

在 Python 中实现并发的步骤

  • 选择正确的策略:确定您的软件是受 CPU 限制还是受 I/O 限制。多进程适用于 CPU 密集型任务,而线程适用于 I/O 密集型操作。
  • 导入相应的库:根据您的方法,导入 asyncio、threading 或 multiprocessing 库。
  • 建立工作角色:指定代表您希望并行执行的任务的过程或函数。
  • 构建线程、进程和任务:您可以启动和构建线程、进程或异步任务来并行执行您的工作函数。
  • 控制同步:在使用线程或进程时,要避免共享资源中的数据损坏,请使用锁或信号量等同步技术。
  • 等待作业完成:确保您的主应用程序在继续之前等待所有正在进行的任务完成。

Python 并发示例

基于线程的并发

导入 threading 和 time 模块。有两个例程 count_down 和 print_colors,它们模拟耗时的任务。这些函数以每秒一次的间隔打印倒计时数字和颜色,以模拟耗时的活动。创建两个 Thread 对象 thread_a 和 thread_b,并使用 target 参数将它们分别分配给 count_down 或 print_colors 函数。使用 start() 方法启动这两个线程。这会启动函数的并行执行。为确保主线程在继续之前等待 thread_a 和 thread_b 线程完成,请对每个线程使用 join() 函数。此同步阶段对于防止主程序过早完成是必要的。最后打印一条消息,表明所有线程都已完成。

输出

 
Counting down: 1
Printing color: Red
Counting down: 2Printing color: Blue
Printing color: Green
Counting down: 3
All threads have completed.   

说明

为了同时执行 count_down 和 print_colors,代码创建了两个线程。每个函数都模拟了一个任务,其中每次操作之间有 1 秒的暂停。主线程使用 Join() 等待两个线程完成,然后报告“所有线程都已完成”。

基于进程的并发

该程序演示了使用 cube(n) 函数对数字进行立方计算的能力。如果运行主进程,则会定义一个值列表 [6, 7, 8, 9, 10]。使用 multiprocessing.Pool() 创建一个多处理器池。使用 map() 方法并行地将 cube 函数应用于列表中的每个值,将任务分配给不同的进程。最后,打印输出。

输出

 
[216, 343, 512, 729, 1000]    

说明

该代码利用 multiprocessing 模块,通过使用工作进程池来并行计算列表中数字的立方。map 方法用于在创建工作进程池的同时,将 cube 函数与列表中的所有值并行应用。收集和打印结果显示了并行处理如何加速计算。

基于协程的并发(使用 asyncio)

以下是代码的细分:导入 asyncio 模块以进行异步编程。使用 asyncio await。使用 await asyncio.sleep(1) 定义的异步函数 say_hello(word) 模拟带有一秒延迟的问候。描述 run_tasks() 异步函数。使用 asyncio.gather() 同时调度每个名称的 say_hello 函数。当 __name__ == "__main__" 时,通过使用 asyncio.run(run_tasks()) 使用 asyncio 运行主异步函数。

输出

 
Java
T
Point   

说明

运行此代码后,您会注意到 say_hello 函数会在等待一秒后打印每个单词。由于 asyncio.gather() 同时调度了对 say_hello 的所有调用,因此在延迟一秒后,“Java”、“T”和“Point”的问候语几乎同时打印,这证明了 Python 的非阻塞异步编程。

总之,无论您的 Python 程序是 CPU 密集型还是 I/O 密集型,添加并行性都可以显著提高其速度。正确的策略和 asyncio、threading 和 multiprocessing 等库可以使 Python 程序更具响应性和效率。