119、concurrent.futures:ThreadPoolExecutor 与 ProcessPoolExecutor 统一接口
119、concurrent.futures:ThreadPoolExecutor 与 ProcessPoolExecutor 统一接口
一个让我熬夜到凌晨三点的Bug
去年秋天,我接手了一个数据清洗服务。每天要处理几百万条日志,单线程跑要十几个小时。我心想,这还不简单?直接上多线程,Python的threading模块我熟得很。结果一跑,CPU占用率不到30%,时间反而更长了。我盯着top输出看了半小时,突然意识到:GIL锁在作祟。后来换成多进程,代码改得面目全非,还因为进程间通信踩了一堆坑。
第二天,团队里一个刚毕业的小伙子说:“老大,你试试concurrent.futures?”我半信半疑地改了一版,代码量减少了一半,性能还提升了。那一刻,我决定把这个模块写进我的“真香”清单。
为什么需要统一接口?
先说说痛点。threading和multiprocessing的API设计差异很大。threading.Thread需要手动start()和join(),multiprocessing.Process也类似,但进程间共享数据要加锁、用队列,一不小心就死锁。更烦人的是,当你从多线程切