Python多进程求列表最大值为何远慢于单进程?
多进程求列表最大值反而比单进程慢的问题分析与解决
问题背景
学习Python的multiprocessing模块时,编写了一个程序:先生成随机数列表,再分别用单进程和多进程两种方法查找列表中的最大值。但运行后发现,无论列表长度如何,多进程代码的运行速度总是比单进程慢数百倍。以下是两段尝试的代码:
第一段尝试代码
import random import multiprocessing import time def random_num_list(length=100000): return [random.randint(-13443,435234) for i in range(length)] rando_list = random_num_list() def method1(lst): biggest_num = -13443 for i in lst: if i > biggest_num: biggest_num = i return biggest_num lst1, lst2 = rando_list[:int(len(rando_list)/3)], rando_list[int(len(rando_list)/3):] def partial_process(lst1, lst2): biggest_num = -13443 for i in lst1: if i > biggest_num: biggest_num = i lst2.append(biggest_num) #print("New record added!") def full_process(lst2): biggest_num = -13443 for i in lst2: if i > biggest_num: biggest_num = i print(biggest_num) def method2(lst1,lst2): with multiprocessing.Manager() as manager: lst2 = manager.list(lst2) p1 = multiprocessing.Process(target=partial_process,args=(lst1, lst2)) p2 = multiprocessing.Process(target=full_process,args=(lst2,)) p1.start() p1.join() p2.start() p2.join() if __name__ == '__main__': method2(lst1,lst2) print(method1(rando_list))
第二段尝试代码
def method2(lst): num_processes = multiprocessing.cpu_count() # 进程数匹配CPU核心数 chunk_size = len(lst) // num_processes with multiprocessing.Pool(processes=num_processes) as pool: # 拆分列表为多个块并行处理 results = pool.map(find_max, [lst[i * chunk_size:(i + 1) * chunk_size] for i in range(num_processes)]) return max(results)
问题原因分析
第一段代码的核心问题
- 完全没有并行执行:启动
p1后立刻调用p1.join(),会等待p1完全结束才启动p2,两个进程是串行执行的,反而多了进程创建、销毁的开销。 - 共享内存对象开销极大:使用
manager.list()创建跨进程共享列表,每一次append操作都需要进程间通信(IPC),这部分开销远大于计算本身。 - 逻辑冗余:
partial_process把前1/3列表的最大值追加到后2/3列表中,再用full_process找最大值,其实和单进程直接找整体最大值的逻辑重复,完全没发挥多进程的并行计算优势。
第二段代码的潜在问题
- 缺少依赖函数:代码中未定义
find_max函数,运行会报错。 - 进程开销抵消收益:如果列表长度太小(比如10万级),进程创建、列表分片、数据序列化/反序列化的开销,会远超过并行计算节省的时间。
- 进程数可能过多:
cpu_count()返回的是逻辑核心数(比如8核16线程),开过多进程会导致CPU调度频繁切换,反而降低效率。
优化后的正确实现
以下是修复后的代码,加入计时功能,确保真正并行,并且使用足够大的列表来体现多进程优势:
import random import multiprocessing import time def random_num_list(length=10**7): # 增大列表到1000万条数据 return [random.randint(-13443, 435234) for _ in range(length)] # 单进程求最大值 def single_process_max(lst): max_val = lst[0] for num in lst[1:]: if num > max_val: max_val = num return max_val # 子进程执行的求块最大值函数 def chunk_max(chunk): max_val = chunk[0] for num in chunk[1:]: if num > max_val: max_val = num return max_val # 多进程求最大值 def multi_process_max(lst): num_processes = min(multiprocessing.cpu_count(), 4) # 限制进程数为物理核心数或4,避免调度开销 chunk_size = len(lst) // num_processes chunks = [lst[i*chunk_size : (i+1)*chunk_size] for i in range(num_processes)] # 处理最后一个块的剩余数据 if len(lst) % num_processes != 0: chunks.append(lst[num_processes*chunk_size:]) with multiprocessing.Pool(processes=num_processes) as pool: chunk_results = pool.map(chunk_max, chunks) return max(chunk_results) if __name__ == '__main__': rando_list = random_num_list() # 测试单进程 start_time = time.time() single_max = single_process_max(rando_list) single_time = time.time() - start_time print(f"单进程结果: {single_max}, 耗时: {single_time:.3f}秒") # 测试多进程 start_time = time.time() multi_max = multi_process_max(rando_list) multi_time = time.time() - start_time print(f"多进程结果: {multi_max}, 耗时: {multi_time:.3f}秒") print(f"多进程比单进程快{single_time/multi_time:.2f}倍" if multi_time < single_time else "多进程未体现优势,请增大列表长度")
关键优化点
- 确保真正并行:使用
Pool批量管理进程,自动分配任务,避免手动join导致的串行。 - 避免不必要的共享内存:直接传递列表分片给子进程,利用Python的复制-on-write机制减少数据拷贝开销,子进程计算完成后只返回单个最大值,而非共享列表。
- 控制进程数:限制进程数为物理核心数(而非逻辑核心数),避免过度调度。
- 使用足够大的计算量:只有当列表足够大(比如1000万条以上),并行计算的收益才会超过进程开销。
内容的提问来源于stack exchange,提问作者Fsksksksss Ssksksksksksksk
相关产品推荐
相关产品推荐

