Windows11下VSCode中Pandas DataFrame多进程预测异常排查
问题描述
在Windows 11系统的Visual Studio Code中运行Python代码时遇到以下问题:
- 需要调用
predict方法测试100个样本,该方法耗时较长,但样本间无依赖、变量无修改,具备并行化条件 predict需访问hlcs/hlcs_clean等变量,尝试通过参数传入后,调用multiprocessing.Pool.map()程序无限运行,调试界面清空;但单线程运行完全正常- 设备有12个物理核心,动态获取
num_process返回24,当前手动设置为12,需排查问题原因
代码与输出
运行代码
import Mains.Main_deap as md import numpy as np import statistics as stat import timeit import warnings import pandas as pd import multiprocessing # 设置参数 size_array_pool = 1 # 种子样本量 runs = 500 # 运行次数 num_best_individuals = 100 # 筛选最优个体数量 # 遗传算法参数 crossover_probability = 0.5 # 交叉概率 mutation_probability = 0.4 # 变异概率 population_size = 200 # 种群规模 num_generations = 100 # 进化代数 # 读取干净数据用于对比 hlcs_clean, llcs_clean = md.read_file("data/file_li.csv") # 错误相关变量定义 number_of_errors = 1 error_types = ["value", "negiert", "index"] selected_error_type = 1 error_type = error_types[selected_error_type] # 定义并行处理样本的函数 def process_sample(sample): if md.predict(hlcs, llcs, sample) != md.predict(hlcs_clean, llcs_clean, sample): return {'error_found': 1, 'error_not_found': 0} else: return {'error_found': 0, 'error_not_found': 1} # 开始计时 start = timeit.default_timer() # 初始化结果统计字典 results_deap = { 'error_found': 0, 'error_not_found': 0 } # 主循环:运行遗传算法并评估样本 for r in range(runs): j = 0 hlcs, llcs = md.read_file("data/file _li.csv") # 生成错误数据 while j < number_of_errors: feedback = md.create_single_error(llcs, error_type) if feedback is None: continue else: j += 1 # 抑制性能警告 warnings.filterwarnings("ignore", category=Warning) array_pool = llcs.get_n_samples_with_labels_random(size_array_pool) array_pool = md.convert_df_from_standard_to_01(hlcs, llcs, array_pool) array_population = array_pool.values # 运行遗传算法 algorithm = md.deap_algorithm(array_population, crossover_probability, mutation_probability, num_best_individuals, population_size, num_generations, hlcs) best_individuals = algorithm.run_algorithm() warnings.resetwarnings() # 打印最优个体的信息(补充原代码缺失的check初始化) check = True if check: print(type(best_individuals[1])) print(f"best_individuals.shape: {best_individuals.shape}") print(type(best_individuals)) check = False # 尝试并行评估样本 pool_results = [] num_processes = 12 pool = multiprocessing.Pool(processes=num_processes) args_list = [(sample, hlcs, llcs, hlcs_clean, llcs_clean) for sample in best_individuals] pool_results.extend(pool.map(process_sample, args_list)) pool.close() pool.join() # 更新结果统计 for result in pool_results: results_deap["error_found"] += result['error_found'] results_deap["error_not_found"] += result['error_not_found'] # 停止计时 stop = timeit.default_timer() # 打印运行时长 print(f"Runtime: {(stop - start)/60} minutes")
输出信息
<class 'pandas.core.series.Series'> best_individuals.shape: (100, 1087) <class 'pandas.core.frame.DataFrame'>
排查与解决思路
1. 参数传递不匹配(直接导致挂起)
你定义的process_sample仅接受sample一个参数,但构建的args_list每个元素是包含5个元素的元组。pool.map()会把整个元组作为单个参数传给process_sample,导致参数不匹配,子进程抛出错误但Windows环境下不会主动暴露错误,表现为程序无限挂起。
- 解决方法二选一:
- 修改
process_sample函数,接收元组参数并解包:def process_sample(args): sample, hlcs, llcs, hlcs_clean, llcs_clean = args if md.predict(hlcs, llcs, sample) != md.predict(hlcs_clean, llcs_clean, sample): return {'error_found': 1, 'error_not_found': 0} else: return {'error_found': 0, 'error_not_found': 1} - 使用
pool.starmap()替代pool.map(),它会自动将元组拆分为多个参数传入函数:pool_results.extend(pool.starmap(process_sample, args_list))
- 修改
2. 缺少Windows多进程主入口判断
Windows下multiprocessing采用spawn方式创建子进程,会重新执行整个脚本。如果没有将主程序逻辑放到if __name__ == '__main__':块中,子进程会再次创建Pool,导致死锁或无限循环。
- 解决方法:将所有主执行代码(从
start = timeit.default_timer()开始到结尾)包裹在主入口判断中:if __name__ == '__main__': # 开始计时 start = timeit.default_timer() # ... 后续所有主逻辑代码 ...
3. 序列化兼容性问题
Windows下子进程需要通过pickle序列化传递对象,如果hlcs/llcs等是自定义类实例或无法被pickle序列化的对象,会导致子进程无法启动,表现为程序挂起。
- 解决方法:
- 检查
hlcs/llcs的类型,确保是可序列化对象(pandas DataFrame/Series默认支持) - 如果涉及自定义类,确保类实现了pickle兼容的序列化逻辑,或者使用
dill库替代默认pickle(需先安装dill,并在代码中配置:multiprocessing.set_start_method('spawn'))
- 检查
4. 资源过载问题
虽然设置了12个进程,但如果每个predict调用占用大量内存/CPU,可能导致系统资源耗尽,进程无响应。可以先将num_processes设为较小值(如4)测试是否能正常运行,再逐步调整。
内容的提问来源于stack exchange,提问作者Delicoius_Cookie
相关产品推荐
相关产品推荐

