并行处理csv分块数据时plt.hist报Given element not in stack错误求助
问题原因分析
你遇到的报错本质是matplotlib的pyplot模块全局状态线程不安全导致的线程竞争问题。
plt模块会在全局维护一套figure、axes的管理栈,你调用plt.hist()时,内部会先调用gca()获取当前全局axes,没有的话就自动创建并加入全局栈。当10个线程同时调用plt.hist()时,多个线程会同时修改同一个全局栈:比如线程1刚查询到某axes不存在准备创建,线程2刚好已经创建并修改了栈结构,线程1后续的栈操作就会找不到预期的元素,触发ValueError: Given element not contained in the stack报错。这种竞争条件本身就是偶现的,所以只会在非首个分块随机触发,和你的数据本身没有关系。
最优解决方案
你调用plt.hist()的目的只是获取直方图的统计结果,不需要实际渲染图像,完全可以直接替换为不涉及任何绘图状态的numpy接口:
把
HistData1, bla1, bla2 = plt.hist(HistogramData, bins=binedges)
替换为
HistData1, bin_edges = np.histogram(HistogramData, bins=binedges)
HistData1的取值和plt.hist()返回的第一个值完全一致,既没有性能损耗,也完全规避了多线程状态冲突问题。
备选方案(如果必须使用matplotlib接口)
如果确有需要保留matplotlib调用,可采用两种方案规避冲突:
- 每个线程使用独立的绘图对象,不调用全局plt接口:在
FindPairs函数内每次创建独立的fig和ax,使用ax.hist()绘制,用完立即关闭fig释放资源:def FindPairs(data): # 原有数据处理逻辑 fig, ax = plt.subplots() HistData1, bla1, bla2 = ax.hist(HistogramData, bins=binedges) plt.close(fig) return HistData1 - 把
ThreadPoolExecutor替换为ProcessPoolExecutor,多进程之间的全局状态完全隔离,不会出现跨进程修改matplotlib全局栈的问题。但注意进程间数据传输有额外开销,仅适合计算量远大于数据传输量的场景。
内容的提问来源于stack exchange,提问作者Hunted
相关产品推荐
相关产品推荐

