在计算机科学领域,并行、串行与并发是描述程序执行方式的重要概念。在 Python 编程中,深入理解这些概念及其实现方式,对于编写高效、性能优越的程序至关重要。进程作为操作系统资源分配和调度的基本单位,在实现并行、串行与并发任务中扮演着核心角色。本文将围绕 Python 进程,详细阐述并行、串行与并发的基本使用方法,并深入剖析背后的原理。
串行执行指的是程序中的任务按照顺序依次执行,一个任务执行完成后,才会开始执行下一个任务。在串行执行模式下,同一时刻只有一个任务在运行,所有任务共享系统资源,这种执行方式简单直观,但在处理多个耗时任务时效率较低。
以下是一个简单的 Python 代码示例,展示了两个任务的串行执行过程:
import time
# 定义任务函数 task1,模拟一个耗时任务
def task1():
print("Task 1 starts")
time.sleep(3) # 模拟任务执行耗时 3 秒
print("Task 1 ends")
# 定义任务函数 task2,模拟一个耗时任务
def task2():
print("Task 2 starts")
time.sleep(2) # 模拟任务执行耗时 2 秒
print("Task 2 ends")
if __name__ == "__main__":
start_time = time.time() # 记录开始时间
task1() # 先执行 task1
task2() # 再执行 task2
end_time = time.time() # 记录结束时间
print(f"Total execution time: {end_time - start_time} seconds")
在上述代码中,task1
和 task2
两个任务依次执行。task1
执行时,task2
处于等待状态;只有当 task1
执行完毕后,task2
才开始执行。整个程序的执行时间为两个任务执行时间之和(约 5 秒)。
并行执行是指多个任务在同一时刻同时执行。在硬件层面,需要多核处理器的支持,每个任务可以分配到不同的 CPU 核心上并行运行,从而充分利用硬件资源,显著提高程序执行效率。
multiprocessing
模块实现并行执行Python 的 multiprocessing
模块提供了创建和管理进程的功能,能够方便地实现并行执行。以下是一个使用 multiprocessing
模块实现两个任务并行执行的示例:
import multiprocessing
import time
# 定义任务函数 task1,模拟一个耗时任务
def task1():
print("Task 1 starts")
time.sleep(3) # 模拟任务执行耗时 3 秒
print("Task 1 ends")
# 定义任务函数 task2,模拟一个耗时任务
def task2():
print("Task 2 starts")
time.sleep(2) # 模拟任务执行耗时 2 秒
print("Task 2 ends")
if __name__ == "__main__":
start_time = time.time() # 记录开始时间
# 创建进程 p1,执行 task1
p1 = multiprocessing.Process(target=task1)
# 创建进程 p2,执行 task2
p2 = multiprocessing.Process(target=task2)
p1.start() # 启动进程 p1
p2.start() # 启动进程 p2
p1.join() # 等待进程 p1 执行完毕
p2.join() # 等待进程 p2 执行完毕
end_time = time.time() # 记录结束时间
print(f"Total execution time: {end_time - start_time} seconds")
在上述代码中,通过 multiprocessing.Process
创建了两个进程 p1
和 p2
,分别执行 task1
和 task2
。两个进程同时启动,在多核处理器环境下,它们会分配到不同的 CPU 核心上并行运行。由于两个任务是并行执行的,整个程序的执行时间约为耗时较长的任务 task1
的执行时间(3 秒)。
在使用 multiprocessing
模块创建进程时,Python 会调用操作系统的底层接口(如 Unix 系统中的 fork
或 Windows 系统中的 CreateProcess
)来创建新进程。每个进程都有自己独立的内存空间、文件描述符等资源,彼此之间相互隔离。操作系统的进程调度器会将不同的进程分配到不同的 CPU 核心上执行,从而实现真正意义上的并行。当进程执行完毕后,操作系统会回收其占用的资源。
并发执行指的是多个任务在一段时间内交替执行,虽然同一时刻只有一个任务在运行,但通过快速切换任务,给用户一种多个任务同时执行的错觉。并发执行不需要多核处理器支持,适用于 I/O 密集型任务(如网络请求、文件读写等),能够有效利用 CPU 等待 I/O 操作完成的空闲时间,提高系统资源利用率。
multiprocessing
模块实现简单并发下面的示例展示了如何通过 multiprocessing
模块模拟并发执行:
import multiprocessing
import time
# 定义任务函数 task,模拟一个 I/O 密集型任务
def task(task_id):
print(f"Task {task_id} starts")
time.sleep(2) # 模拟 I/O 操作耗时 2 秒
print(f"Task {task_id} ends")
if __name__ == "__main__":
start_time = time.time() # 记录开始时间
processes = []
for i in range(3):
p = multiprocessing.Process(target=task, args=(i,)) # 创建进程执行任务
processes.append(p)
p.start() # 启动进程
for p in processes:
p.join() # 等待所有进程执行完毕
end_time = time.time() # 记录结束时间
print(f"Total execution time: {end_time - start_time} seconds")
在上述代码中,创建了 3 个进程执行 task
函数。虽然这些进程在单核处理器上不能真正并行,但操作系统会通过调度算法快速切换进程,使它们交替执行。由于任务是 I/O 密集型(模拟 I/O 等待时间),在一个任务等待 I/O 完成时,CPU 可以切换去执行其他任务,从而提高整体执行效率。
操作系统的进程调度器负责并发任务的切换。当一个进程执行 I/O 操作时(如读取文件或发送网络请求),会进入阻塞状态,此时操作系统会将 CPU 资源分配给其他就绪状态的进程。当 I/O 操作完成后,阻塞的进程会重新进入就绪队列等待调度。通过这种方式,多个任务在宏观上看起来像是同时执行,实现了并发效果。
本文围绕 Python 进程,详细介绍了串行、并行与并发的基本概念、实现方式及原理。串行执行顺序简单,但效率较低;并行执行依赖多核处理器,能大幅提升 CPU 密集型任务的执行效率;并发执行通过任务交替执行,在 I/O 密集型任务中表现出色。通过 multiprocessing
模块,Python 为开发者提供了便捷的工具来实现这三种执行模式。
Dask
、Ray
等库已在大数据和分布式计算领域发挥重要作用。掌握并行、串行与并发的原理和使用方法,是 Python 开发者提升程序性能、应对复杂任务的关键。随着技术的不断发展,这些概念和技术也将在更多领域发挥重要作用。