Mac下Python多进程线性搜索出现应用内存不足问题排查
单进程与多进程线性搜索性能测试问题分析
问题描述
我正在编写程序对比单进程与多进程实现线性搜索的性能。在搭载M2芯片、16GB内存、12核的MacBook Pro上运行时,弹出"应用内存不足"错误,进程甚至未启动;使用较小的nums数组时,进程可运行但多进程版本速度反而更慢。我希望测试大规模场景(小规模下进程开销会抵消性能提升),请问我哪里操作有误?
提供的代码
import random import math import time from multiprocessing import Process, Value import os def fastLinearSearch(nums, startIndex, randNumToFind, chunkSize, foundNumber, start_time): print('start index: ' + str(startIndex)) print('chunk size: ' + str(chunkSize)) if foundNumber == randNumToFind: print('done with ' + str(os.getpid())) return for i in range(startIndex, startIndex + chunkSize): if foundNumber == randNumToFind: print('done with ' + str(os.getpid())) return if randNumToFind == nums[i]: print('Found number ' + str(randNumToFind)) print("Took " + str(time.time() - start_time) + " seconds") foundNumber = randNumToFind print('done with ' + str(os.getpid())) return print("done and didn't find anything with pid: " + str(os.getpid())) if __name__ == '__main__': nums = [] print('Generating nums array') for i in range(1000000000): nums.append(i) print('Nums array generated') # mix up numbers # print("Mixing up numbers...") # random.shuffle(nums) # print('Mixed up numbers') randNum = math.floor(random.random() * len(nums)) # regular linear search print("Linear search for number " + str(randNum)) start_time = time.time() for i in range(len(nums)): if (nums[i] == randNum): print("Found " + str(randNum)) print("Took " + str(time.time() - start_time) + " seconds") break # multiprocessing linear search print("Fast linear search for number " + str(randNum)) start_index_1 = 0 processes_count = 4 start_index_2 = math.floor(len(nums) / processes_count) * 1 start_index_3 = math.floor(len(nums) / processes_count) * 2 start_index_4 = math.floor(len(nums) / processes_count) * 3 chunkSize = math.floor(len(nums) / processes_count) start_time = time.time() foundNumber = Value('d', -1) # start at -1, a change shows it was found p1 = Process(target=fastLinearSearch, args=( nums, start_index_1, randNum, chunkSize, foundNumber, start_time)) p2 = Process(target=fastLinearSearch, args=( nums, start_index_2, randNum, chunkSize, foundNumber, start_time)) p3 = Process(target=fastLinearSearch, args=( nums, start_index_3, randNum, chunkSize, foundNumber, start_time)) p4 = Process(target=fastLinearSearch, args=( nums, start_index_4, randNum, chunkSize, foundNumber, start_time)) p1.start() p2.start() p3.start() p4.start() p1.join() p2.join() p3.join() p4.join()
错误点分析
1. 内存占用超限
- 生成10亿元素的列表
nums,每个Python int对象(小整数)约占28字节,10亿个元素总内存约28GB,远超你的16GB内存,直接触发"内存不足"错误。 - 多进程模式下,Unix系统默认用
fork创建子进程,虽然是写时复制,但父进程在创建子进程前已完全生成并修改了nums列表,会导致每个子进程复制整个列表,内存占用直接翻4倍,进一步加剧内存耗尽问题。
2. 共享变量使用错误
- 代码中直接用
foundNumber == randNumToFind比较,foundNumber是Value对象,不是数值,应该访问其.value属性(即foundNumber.value == randNumToFind)。 - 修改共享变量时,
foundNumber = randNumToFind只是给局部变量赋值,并未修改共享内存中的值,其他进程无法感知目标已找到,会继续无效遍历。
3. 进程逻辑冗余与开销问题
- 即使某个进程找到目标,其他进程无法及时终止,因为共享变量未正确更新,导致不必要的计算浪费。
- 小规模数组场景下,进程创建、内存复制的开销远大于线性搜索本身的耗时,直接导致多进程版本更慢。
4. 测试场景不真实
- 代码中
nums是有序的(未执行shuffle),单进程搜索完全不需要遍历,直接通过randNum即可定位,这会让单进程测试结果失真,无法真实对比性能。
优化建议
1. 内存优化
- 避免生成超大列表:如果是模拟无序场景,可以用生成器或直接通过逻辑判断元素值,不需要存储全部元素;如果必须用数组,使用
multiprocessing.Array或shared_memory实现内存共享,避免每个进程复制数据。 - 缩小测试规模先验证逻辑:比如先测试1000万元素的数组,确认多进程逻辑正确后再逐步放大。
2. 修复多进程逻辑
- 正确使用共享变量:所有对
foundNumber的访问和修改都要操作.value属性。 - 增加进程退出判断:在遍历循环中定期检查
foundNumber.value,一旦发现目标已找到就立即退出。 - 使用
Pool管理进程:替代手动创建多个Process,代码更简洁,且能自动处理进程调度。
3. 测试场景修正
- 确保数组是无序的:取消
shuffle的注释,让线性搜索的场景更真实,否则有序数组应该用二分搜索,线性搜索没有对比意义。 - 多进程测试前先释放单进程的内存:单进程测试完成后,手动删除
nums并调用gc.collect()回收内存,再启动多进程测试,避免内存叠加。
内容的提问来源于stack exchange,提问作者Drew Gallagher
相关产品推荐
相关产品推荐

