Python多进程编程实战:从单线程阻塞到并行处理

周末不加班
周末不加班
发布时间:2026-10-12| 3人浏览过
原创

本文深入解析Python中的多进程概念,通过对比单线程顺序执行与多进程并行执行的耗时差异,演示如何使用os.fork()及multiprocessing.Process实现任务并行化。文章涵盖进程创建、父进程与子进程返回值的区别,以及通过join等待子进程完成的具体代码示例,帮助开发者理解如何利用多核CPU提升程序执行效率。

现代操作系统均具备“多任务”处理能力,在操作系统视角下,每一个运行的程序实例被称为一个进程(process)。例如,启动浏览器即意味着创建并运行了一个浏览器进程。

若将计算机的核心CPU比作一座工厂,那么进程就如同工厂内的车间,代表CPU当前处理的一个独立任务。在任意特定时刻,CPU仅能执行一个进程,其余进程则处于非运行状态(如就绪或阻塞状态)。

读者可能会产生疑惑:既然CPU同一时刻只运行一个进程,为何我们在浏览网页时,后台的音乐播放器依然能正常播放声音?

这实际上是操作系统采用时间片轮转机制的结果。操作系统让各个任务交替执行:任务1执行0.01秒后切换至任务2,任务2执行0.01秒后再切换至任务3,如此循环往复。由于CPU的处理速度极快,这种快速的交替执行给用户造成了所有任务“同时”运行的错觉。

Python中的多进程实现

在UNIX或Linux操作系统中,可以通过调用fork()函数来创建新进程。与普通函数调用一次返回一次不同,fork()函数调用一次却返回两次:操作系统会自动复制当前进程(称为父进程)生成一个新进程(称为子进程),随后分别在父进程和子进程的上下文中返回。

在fork()的返回结果中,子进程始终返回0,而父进程则返回新创建子进程的ID。这样设计的理由是,一个父进程可以fork出多个子进程,因此父进程需要记录每个子进程的ID以便管理;而子进程只需调用getppid()即可获取其父进程的ID。

fork()函数被封装在Python的os模块中。下面通过具体示例,对比使用多进程与不使用多进程在性能上的区别:

from random import randint

from time import time, sleep

def download_task(filename):

print('开始下载%s...' % filename)

time_to_download = randint(5, 10)

sleep(time_to_download)

print('%s下载完成! 耗费了%d秒' % (filename, time_to_download))

def main():

start = time()

download_task('MySQL从删库到跑路.pdf')

download_task('万万没想到.mp4')

end = time()

print('总共耗费了%.2f秒.' % (end - start))if __name__ == '__main__':

main()

执行结果如下:

开始下载MySQL从删库到跑路.pdf...

MySQL从删库到跑路.pdf下载完成! 耗费了9秒

开始下载万万没想到.mp4...

万万没想到.mp4下载完成! 耗费了9秒

总共耗费了18.00秒.

从上述示例可见,若代码仅按顺序依次执行,即使两个下载任务互不相关,也必须等待第一个文件下载完成后才能开始第二个任务。这种方式显然缺乏效率且不合理。接下来,我们将使用多进程方式将两个下载任务分配到不同的进程中并行执行,代码如下:

from multiprocessing import Process

from os import getpid

from random import randint

from time import time, sleep

def download_task(filename):

print('启动下载进程,进程号[%d].' % getpid()) print('开始下载%s...' % filename) time_to_download = randint(5, 10)

sleep(time_to_download)

print('%s下载完成! 耗费了%d秒' % (filename, time_to_download))

def main():

start = time()

p1 = Process(target=download_task, args=('MySQL从删库到跑路.pdf', ))

p1.start()

p2 = Process(target=download_task, args=('万万没想到.mp4', ))

p2.start()

p1.join()

p2.join()

end = time()

print('总共耗费了%.2f秒.' % (end - start))

if __name__ == '__main__': main()

多进程执行结果如下:

启动下载进程,进程号[568408].

开始下载万万没想到.mp4...万万没想到.

mp4下载完成! 耗费了6秒

启动下载进程,进程号[565896].

开始下载MySQL从删库到跑路.

pdf...MySQL从删库到跑路.pdf下载完成! 耗费了10秒

总共耗费了10.09秒.

运行上述代码可以明显观察到,两个下载任务几乎是“同时”启动的。由于并行处理,程序的总执行时间大幅缩短,不再等于两个任务耗时的简单相加,而是接近耗时较长的那个任务的时间。

以上就是Python多进程学习笔记的详细内容,更多关于Python多进程的高级用法与资料,请关注本站其他相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。