Python 多进程(Process)基础
1️⃣ 程序、进程与线程的基本概念
| 名称 | 概念 |
|---|---|
| 程序(Program) | 一组指令的有序集合(如.py文件),是静态的 |
| 进程(Process) | 程序运行后在内存中分配资源的实例,包含代码、数据和系统资源,是动态的 |
🔸 结论:
- 程序 → 启动后变成 → 进程
2️⃣ 创建子进程的方式:multiprocessing.Process
from multiprocessing import Process
📌 基本语法:
p = Process(group=None, target=函数名, name='进程名', args=(位置参数元组,), kwargs={关键字参数字典})
📌 参数说明:
| 参数 | 含义 |
|---|---|
group |
分组功能(基本不用,默认 None) |
target |
子进程要执行的函数 |
name |
子进程名称,默认是 Process-N |
args |
传给函数的位置参数(元组) |
kwargs |
传给函数的关键字参数(字典) |
3️⃣ 常用方法和属性
| 方法/属性 | 说明 |
|---|---|
start() |
启动子进程 |
join(timeout) |
主进程等待子进程执行结束(可设置最大等待时间) |
is_alive() |
检查子进程是否还在运行 |
terminate() |
强制终止子进程 |
pid |
获取子进程的 PID |
name |
获取进程名称 |
run() |
若没有指定 target,默认执行 run 方法 |
4️⃣ 基本示例:创建并运行子进程
from multiprocessing import Process
import os, time
def task(name):
print(f'子进程运行中:{name}, PID={os.getpid()}, 父PID={os.getppid()}')
time.sleep(1)
if __name__ == '__main__':
print("主进程开始")
for i in range(3):
p = Process(target=task, args=(f"任务{i+1}",))
p.start()
print(f"{p.name} 是否还活着?", p.is_alive())
p.join() # 阻塞主进程,等子进程结束
print(f"{p.name} 结束后是否还活着?", p.is_alive())
print("主进程结束")
---
# 示例输出:
主进程开始
Process-1 是否还活着? True
子进程运行中:任务1, PID=25904, 父PID=8636
Process-1 结束后是否还活着? False
Process-2 是否还活着? True
子进程运行中:任务2, PID=13788, 父PID=8636
Process-2 结束后是否还活着? False
Process-3 是否还活着? True
子进程运行中:任务3, PID=24928, 父PID=8636
Process-3 结束后是否还活着? False
主进程结束
5️⃣ 不传 target 的情况下 run() 的行为
from multiprocessing import Process
p = Process() # 未传 target
p.start() # 只会调用 Process 内部默认的 run(),不会执行任务
🧠 说明:
- 如果不传
target,start()只会调用默认的run()方法,不执行任何具体函数代码
6️⃣ 自定义类并重写 run() 方法
适用于更复杂的子进程管理,推荐使用。
from multiprocessing import Process
import os
class MyProcess(Process):
def __init__(self, name):
super().__init__()
self.name = name
def run(self):
print(f'子进程:{self.name}, PID={os.getpid()}, 父PID={os.getppid()}')
if __name__ == '__main__':
print("主进程启动")
for i in range(1, 4):
p = MyProcess(name=f"自定义进程-{i}")
p.start()
p.join()
print("主进程结束")
---
#示例输出:
主进程启动
子进程:自定义进程-1, PID=21540, 父PID=1612
子进程:自定义进程-2, PID=31500, 父PID=1612
子进程:自定义进程-3, PID=6528, 父PID=1612
主进程结束
7️⃣ terminate() 方法 —— 强制终止进程
from multiprocessing import Process
import os, time
def task(name):
print(f"子进程运行中:{name}, PID={os.getpid()}")
time.sleep(3)
if __name__ == '__main__':
p = Process(target=task, args=("被终止的任务",))
p.start()
time.sleep(1) # 给子进程1秒时间运行
p.terminate() # 强制终止
print(f"{p.name} 已被终止")
⚠️ 注意:
terminate()是强制终止,不能保证资源完全释放,慎用!- 常见用在进程卡死或死循环时
8️⃣ 主进程等待所有子进程结束(使用 join)
-
主进程和子进程是并发运行的,主进程不会自动等待子进程完成。
-
如果希望主进程等待子进程完成,需要在启动子进程后调用
.join()。
from multiprocessing import Process
import os, time
def task():
print(f"子进程PID={os.getpid()}, 父PID={os.getppid()}")
time.sleep(1)
if __name__ == '__main__':
print("主进程启动")
process_list = []
for _ in range(5):
p = Process(target=task)
p.start()
process_list.append(p)
for p in process_list:
p.join() # 主进程等待所有子进程完成
print("主进程结束")
✅ 进程小结
| 项目 | 说明 |
|---|---|
| 启动进程 | p.start() |
| 等待进程完成 | p.join() |
| 判断进程是否活着 | p.is_alive() |
| 强制结束进程 | p.terminate() |
| 创建进程的方式 | 1. 传 target 运行函数 2. 重写 run 方法 |
| 主子进程关系 | 主进程不会自动等待子进程,需显式 join |
9️⃣ 进程池:multiprocessing.Pool
适合大量任务,避免创建过多进程导致资源浪费。
✅ 基本用法-非阻塞的方式
# 创建进程
from multiprocessing import Pool
import os,time
# 编写任务
def task(name):
print(f'子进程的pid:{os.getpid()},执行任务:{name}')
time.sleep(1)
if __name__ == '__main__':
# 主进程
start=time.time()
print('父进程开始执行')
# 创建进程池
p=Pool(3)
# 创建任务
for i in range(10):
# 以非阻塞的方式
p.apply_async(func=task,args=(i,))
p.close() # 关闭进程池不在接收新任务
p.join() # 阻塞父进程,等待所有的子进程执行完毕之后,才会执行父进程中的代码
print('所有的子进程执行完毕,父进程执行结束')
print(time.time()-start)
----
示例输出:
父进程开始执行
子进程的pid:9908,执行任务:0
子进程的pid:15876,执行任务:1
子进程的pid:12668,执行任务:2
子进程的pid:9908,执行任务:3
子进程的pid:15876,执行任务:4
子进程的pid:12668,执行任务:5
子进程的pid:9908,执行任务:6
子进程的pid:15876,执行任务:7
子进程的pid:12668,执行任务:8
子进程的pid:9908,执行任务:9
所有的子进程执行完毕,父进程执行结束
4.1847922801971436
✅ 基本用法-阻塞的方式
# 创建进程
from multiprocessing import Pool
import os,time
# 编写任务
def task(name):
print(f'子进程的pid:{os.getpid()},执行任务:{name}')
time.sleep(1)
if __name__ == '__main__':
# 主进程
start=time.time()
print('父进程开始执行')
# 创建进程池
p=Pool(3)
# 创建任务
for i in range(10):
# 以阻塞的方式
p.apply(func=task,args=(i,))
p.close() # 关闭进程池不在接收新任务
p.join() # 阻塞父进程,等待所有的子进程执行完毕之后,才会执行父进程中的代码
print('所有的子进程执行完毕,父进程执行结束')
print(time.time()-start)
-----
示例输出:
父进程开始执行
子进程的pid:4484,执行任务:0
子进程的pid:27940,执行任务:1
子进程的pid:31964,执行任务:2
子进程的pid:4484,执行任务:3
子进程的pid:27940,执行任务:4
子进程的pid:31964,执行任务:5
子进程的pid:4484,执行任务:6
子进程的pid:27940,执行任务:7
子进程的pid:31964,执行任务:8
子进程的pid:4484,执行任务:9
所有的子进程执行完毕,父进程执行结束
10.161132097244263
✅ 方法说明
| 方法名 | 说明 |
|---|---|
apply_async() |
非阻塞提交任务(推荐) |
apply() |
阻塞提交(等待上一个任务完成才继续) |
close() |
关闭进程池,不能再添加任务 |
join() |
等待子进程完成(要放在 close() 后面) |
terminate() |
立即终止所有进程(会中断任务) |
🔟并发 vs 并行(易混概念)
| 概念 | 说明 |
|---|---|
| 并发 | 多任务交替执行,逻辑上同时进行(如一个 CPU 快速切换任务) |
| 并行 | 多任务真正同时执行(如多核 CPU 各自处理一个任务) |
📌 举例:
-
并发:你一边做饭,一边接电话,但不是同时操作
-
并行:你做饭,朋友接电话,同时进行

浙公网安备 33010602011771号