如何并行处理CSV文件?排查Python并行验证代码的潜在问题
咱们来一步步拆解你这份并行代码里的坑,这些都是多进程编程里很容易踩的点:
1. 多进程写入同一文件的致命问题
你的open_csv函数里,每个进程都用open("output.txt", 'w')打开文件——'w'模式会直接截断清空文件。这意味着第一个进程刚写了点内容,第二个进程一打开文件就把前面的内容全删了,最后你只会看到最后一个完成的进程的输出。就算改成'a'追加模式,也会因为多个进程同时写入没有锁保护,导致内容乱序、重叠(比如两个进程同时写,一行内容被拆成两半混在一起)。
修复方案:
- 让每个进程先把自己的结果写到临时文件,所有进程完成后再合并到
output.txt; - 或者用
multiprocessing.Queue,每个进程把结果放到队列里,主进程单独负责从队列读取并写入文件,这样就避免了多进程写同一文件的竞态。
2. 进度输出混乱
多个进程同时打印Processing file X/Y,这些输出会互相穿插,你会看到一堆乱糟糟的进度信息,根本没法区分哪个进程在处理哪个文件。
修复方案:
- 用主进程统一管理进度:每个子进程完成一个文件就给主进程发一个信号,主进程更新并打印全局进度;
- 或者给每个进程分配唯一标识,打印时带上进程ID,比如
[Process 2] Processing file 5/200,这样至少能区分不同进程的进度输出。
3. 未处理子进程的stderr导致阻塞
你在并行代码里去掉了stderr=subprocess.PIPE,但如果Scala脚本有错误输出,子进程的stderr缓冲区会被填满,导致子进程卡住无法继续运行。串行代码里是捕获了stderr的,并行版本漏掉了这个关键处理。
修复方案:
- 在
subprocess.Popen里加上stderr=subprocess.PIPE,并用communicate()替代直接read(),避免死锁:
validator = subprocess.Popen( [PATH_TO_VALIDATOR, os.path.join(PATH_TO_CSV_FOLDER, filename), PATH_TO_CSV_SCHEMA, "--csv-encoding", CSV_ENCODING, "--csv-schema-encoding", CSV_SCHEMA_ENCODING, '--fail-fast', 'true'], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) result, err = validator.communicate() output.write(result.decode('windows-1252')) # 可选:把错误信息也写入输出,方便排查问题 if err: output.write(f"\nError in {filename}: {err.decode('windows-1252')}\n")
4. 主进程未等待子进程完成
你的主进程启动完所有子进程后就直接退出了,虽然Windows下子进程可能会继续运行,但如果用户关闭控制台,所有子进程都会被强制终止,你没法确保所有文件都处理完成。
修复方案:
- 把所有进程对象存到列表里,启动后循环调用
join()等待每个进程完成:
processes = [] for csv_list in split_csv_directory: p = multiprocessing.Process(target=open_csv, args=(csv_list,)) p.start() processes.append(p) # 等待所有子进程执行完毕 for p in processes: p.join()
5. 路径拼接不安全
你用PATH_TO_CSV_FOLDER + "/" + filename拼接路径,Windows下路径分隔符是\,如果PATH_TO_CSV_FOLDER末尾已经有\,就会变成C:\...\\/filename这种错误路径,导致Scala脚本找不到文件。
修复方案:
- 用Python内置的
os.path.join()拼接路径,它会自动根据系统选用正确的分隔符:
os.path.join(PATH_TO_CSV_FOLDER, filename)
6. 函数内的import不规范
你的open_csv函数里把import subprocess放在函数内部,虽然语法合法,但每次调用函数都会重新导入一次,没必要,也不符合Python编码规范。应该把所有import语句放在文件顶部。
这些问题里,前两个是最影响功能的——文件内容被覆盖或乱序,以及进度混乱,建议优先解决。
内容的提问来源于stack exchange,提问作者user4458727

