1. 为啥要用多进程?先认清GIL
Python多线程为何没法加速CPU密集型任务?因为GIL(全局解释器锁):在主流的CPython解释器中,无论多少线程归根结底同时只有一个线程在执行Python字节码,严重影响CPU计算性能的并行。
多进程机制完美绕开了GIL:每个进程拥有自己的Python解释器和内存空间,真正多核、多CPU并行执行,CPU密集型任务大大提速!
2. Python多进程基础用法:multiprocessing库
Python 内置标准库 multiprocessing
,API与threading
非常类似,上手容易。
2.1 Proces介绍:
Process([group [, target [, name [, args [, kwargs]]]]])
- target 表示调用对象
- args 表示调用对象的位置参数元组
- kwargs 表示调用对象的字典
- name 为别名
- group 实质上不使用
2.2 Hello,多进程
python
from multiprocessing import Process
import os
def worker():
print('子进程PID:', os.getpid())
if __name__ == '__main__':
p = Process(target=worker)
p.start()
p.join()
print('主进程结束')
注意! Windows下多进程要写在 if __name__ == '__main__':
保护块内,否则会无限递归启动进程。
2.3 多进程并行计算
python
from multiprocessing import Process
import time
def task(name):
print(f'{name} 开始')
time.sleep(2)
print(f'{name} 结束')
if __name__ == '__main__':
proc_list = []
for i in range(3):
p = Process(target=task, args=(f'进程{i+1}',))
p.start()
proc_list.append(p)
for p in proc_list:
p.join()
print('所有子进程结束')
多个进程可并发分担任务,真正多核利用!
2.4 子进程类实现(面向对象)
python
import multiprocessing
import time
class ClockProcess(multiprocessing.Process):
def __init__(self, interval):
multiprocessing.Process.__init__(self)
self.interval = interval
def run(self):
n = 5
while n > 0:
print("当前时间: {0}".format(time.ctime()))
time.sleep(self.interval)
n -= 1
if __name__ == '__main__':
p = ClockProcess(3)
p.start()
3. 进阶:进程池批量并行(Process Pool)
大量任务并发时,手动管理进程很麻烦,用Pool
池自动分配和收集结果,极大提升效率!
python
from multiprocessing import Pool
import os, time
def square(n):
print('计算', n, '在进程', os.getpid())
time.sleep(1)
return n * n
if __name__ == '__main__':
with Pool(processes=3) as pool:
results = pool.map(square, range(5))
print('返回结果:', results)
比循环创建 Process
简洁得多,还能自动分配CPU,每个子进程并发执行给定任务。
4. 多进程间数据:通信与共享
- 每个进程独立内存,不能像多线程那样直接共享变量
- 多进程用队列(Queue)、管道(Pipe)或特殊共享对象实现
4.1 用队列 Queue 通信(推荐)
python
from multiprocessing import Process, Queue
def producer(q):
for i in range(5):
q.put(i)
q.put(None) # 发送结束标记
def consumer(q):
while True:
item = q.get()
if item is None:
break
print('消费:', item)
if __name__ == '__main__':
q = Queue()
p1 = Process(target=producer, args=(q,))
p2 = Process(target=consumer, args=(q,))
p1.start()
p2.start()
p1.join()
p2.join()
4.2 共享内存变量:Value 与 Array
python
from multiprocessing import Process, Value, Array
def worker(val, arr):
val.value += 10
for i in range(len(arr)):
arr[i] *= 2
if __name__ == '__main__':
num = Value('i', 5) # int类型共享变量
arr = Array('i', [1, 2, 3, 4]) # 数组
p = Process(target=worker, args=(num, arr))
p.start()
p.join()
print('num =', num.value)
print('arr =', list(arr))
5. 多进程安全:锁机制
多进程也需防止竞争条件,通过 Lock/Manager 加锁同步。
python
from multiprocessing import Process, Lock, Value
def add(lock, counter):
for _ in range(100000):
with lock:
counter.value += 1
if __name__ == '__main__':
lock = Lock()
counter = Value('i', 0)
procs = [Process(target=add, args=(lock, counter)) for _ in range(4)]
for p in procs:
p.start()
for p in procs:
p.join()
print('结果:', counter.value)
6. 多进程vs多线程,该如何选?
- CPU密集(数值计算/图像处理/大数据科学):用多进程"跑满CPU"突破GIL
- IO密集(爬虫/网络/磁盘/数据库交互):多线程即可,更省内存和切换开销
点个赞,关注我获取更多实用 Python 技术干货!如果觉得有用,记得收藏本文!