matplotlib的savefig是线程安全的吗?

3
我有一个内部分布式计算库,我们经常用它来进行并行计算任务。在进程被分割后,它们运行数据加载和计算步骤,最后完成“保存”步骤。通常这涉及将数据写入数据库表中。
但是对于特定的任务,我需要每个进程的输出是一些数据图的.png文件。总共有95个进程,因此有95个.png文件。
在我的“保存”步骤中(在每个进程上执行),我有一些非常简单的代码,使用matplotlib的boxplot函数制作箱线图和一些使用savefig将其写入具有基于该过程中使用的特定数据的唯一名称的.png文件的代码。
然而,我偶尔会看到输出,其中似乎两个或更多组数据被写入了同一个输出文件,尽管名称是唯一的。
matplotlib是否在制作箱线图或保存图像时使用临时文件保存?如果是这样,它是否总是使用相同的临时文件名(从而导致覆盖冲突)?我已经使用strace运行了我的进程,并没有看到任何明显的来自matplotlib的临时文件写入。
如何确保这是线程安全的?我绝对希望以并行方式进行文件保存,因为我希望大大扩展输出.png文件的数量,因此首先存储所有数据,然后仅串行执行绘图/保存部分的选项非常不可取。
我无法重现我们正在使用的完整并行基础设施,但下面是被调用以创建绘图句柄的函数,以及被调用以保存绘图的函数。为了问题的缘故,您应该假设线程安全与我们的分布式库无关。我们知道它不是来自我们的代码,我们已经使用它进行多处理作业多年,并且没有像这样的线程问题(特别是对于我们不直接控制的任何matplotlib的临时文件)。
import pandas
import numpy as np
import matplotlib.pyplot as plt

def plot_category_data(betas, category_name):
    """
    Function to organize beta data by date into vectors and pass to box plot
    code for producing a single chart of multi-period box plots.
    """
    beta_vector_list = []
    yms = np.sort(betas.yearmonth.unique())
    for ym in yms:
        beta_vector_list.append(betas[betas.yearmonth==ym].Beta.values.flatten().tolist())
    ###

    plot_output = plt.boxplot(beta_vector_list)
    axs = plt.gcf().gca()
    axs.set_xticklabels(betas.FactorDate.unique(), rotation=40, horizontalalignment='right')
    axs.set_xlabel("Date")
    axs.set_ylabel("Beta")
    axs.set_title("%s Beta to BMI Global"%(category_name))
    axs.set_ylim((-1.0, 3.0))

    return plot_output
### End plot_category_data

def save(self):
    """
    Make calls to store the plot to the desired output file.
    """
    out_file = self.output_path + "%s.png"%(self.category_name)
    fig = plt.gcf()
    fig.set_figheight(6.5)
    fig.set_figwidth(10)
    fig.savefig(out_file, bbox_inches='tight', dpi=150)
    print "Finished and stored output file %s"%(out_file)
    return None
### End save
1个回答

1
在你的两个函数中,你调用了plt.gcf()。我建议每次使用plt.figure()生成一个新图,并明确引用该图,这样就可以完全避免整个问题。

不,这些进程使用的是不同的内存。gcf()gca() 引用的是内存中最新的图表... 因此,不同的实例无法看到彼此在内存中的图形等内容。 - ely
你能否验证一下matplotlib是否使用特定的临时文件来引用同一个当前图形?这将是它在不同处理器上创建问题的唯一方式。 - ely
抱歉,我以为你说你正在使用线程。即便如此,你需要使用最新的图形有什么原因吗? - thyme
1
没有特别的原因,但这不应该有影响。我正在使用线程和多进程。每个进程只有一个图表,所以 gcf 应该只引用那个图表。我可以很容易地将其更改为给定特定的图形句柄,但我更担心的是它在事务的 savefig 部分,除非有一些记录的理由认为 gcf 使用临时文件,这些文件会在不同的进程之间被覆盖。 - ely

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接