【问题标题】:python pandas dataframe thread safe?python pandas数据帧线程安全吗?
【发布时间】:2012-11-27 20:38:31
【问题描述】:

我正在使用多个线程来访问和删除我的 pandas 数据框中的数据。因此,我想知道 pandas 数据帧是线程安全的吗?

【问题讨论】:

    标签: python thread-safety pandas


    【解决方案1】:

    不,pandas 不是线程安全的。而且它以令人惊讶的方式不是线程安全的。

    • 我可以在另一个线程正在使用时从 pandas 数据帧中删除吗?

    胡思乱想!没有。而且一般不会。甚至对于 GIL 锁定的 python 数据结构也不行。

    • 我可以在其他人写入的同时读取 pandas 对象吗?
    • 我可以在我的线程中复制一个 pandas 数据框,然后处理该副本吗?

    绝对不是。有一个长期悬而未决的问题:https://github.com/pandas-dev/pandas/issues/2728

    实际上,我认为这是非常合理(即预期)的行为。我不希望能够同时写入和读取或复制任何数据结构,除非:i)它是为并发设计的,或者 ii)我对该对象具有排他锁 和所有视图派生自它的对象.loc.iloc 是视图,pandas 可能还有其他)。

    • 我可以在没有其他人写入的情况下读取 pandas 对象吗?

    对于 Python 中的几乎所有数据结构,答案都是肯定的。对于熊猫,没有。看来,目前还不是设计目标。

    通常,如果没有人执行变异操作,您可以对对象执行“读取”操作。不过,你必须要小心一点。一些数据结构,包括 pandas,执行记忆,以缓存昂贵的操作,否则这些操作在功能上是纯的。在 Python 中实现无锁记忆通常很容易:

    @property
    def thing(self):
        if _thing is MISSING:
            self._thing = self._calc_thing()
        return self._thing
    

    ...它简单且安全(假设赋值是安全原子的——并非所有语言都如此,但在 CPython 中是这样,除非您覆盖 __setattribute__)。

    Pandas、系列和数据帧索引在首次使用时会延迟计算。我希望(但我在文档中看不到保证)它们是以类似的安全方式完成的。

    对于所有库(包括 pandas),我希望如果没有人执行变异,所有类型的只读操作(或更具体地说,“功能纯”操作)都是线程安全的操作。我认为这是一个“合理的”容易实现的、常见的、较低的线程安全标准。

    但是,对于 pandas,您不能假设这一点。 即使您可以保证没有人对您的对象执行“功能不纯”的操作(例如写入单元格、添加/删除列),pandas 也不是线程安全的。

    这是一个最近的例子:https://github.com/pandas-dev/pandas/issues/25870(它被标记为 .copy-not-threadsafe 问题的重复,但它似乎可能是一个单独的问题)。

    s = pd.Series(...)
    f(s)  # Success!
    
    # Thread 1:
       while True: f(s)  
    
    # Thread 2:
       while True: f(s)  # Exception !
    

    ... f(s): s.reindex(..., copy=True) 失败,它将结果 a 作为新对象返回——你会认为它在功能上是纯的和线程安全的。不幸的是,事实并非如此。

    这样做的结果是,我们无法在生产环境中将 pandas 用于我们的医疗保健分析系统 - 我现在不鼓励将它用于内部开发,因为它会使只读操作的内存中并行化不安全。 (!!)

    reindex 的行为既奇怪又令人惊讶。如果有人知道为什么会失败,请在这里回答:What's the source of thread-unsafety in this usage of pandas.Series.reindex(, copy=True)?

    维护人员将此标记为 https://github.com/pandas-dev/pandas/issues/2728 的副本。我很怀疑,但如果 .copy 是源,那么 几乎所有的 pandas 在任何情况下都不是线程安全的(这是他们的建议)。

    【讨论】:

    • 啊。 所以这可以解释一些事情...... 即最近几周不一致的单元测试结果。 :(
    • 那么只用锁包起来怎么样?这会使性能不合理地变差吗?回复:为您的用例完全放弃 pandas。
    • 也许......但需要注意的是:Python 通常不会执行并行执行,即使在多线程程序中也是如此。 Numpy 和许多 C 优化库通过在 C 语言中执行并行处理来解决这个问题。因为很多 Pandas 都是用 Python 实现的,所以 GIL + 线程可能不会提供很大的好处(你需要尝试知道)。此外,尚不清楚哪些 pandas 操作维护对输入对象的引用,因此使用锁进行包装可能并不总能提供您希望的内存访问安全性。线程使用不是设计目标,也没有记录。 悲伤的长号
    • 悲伤的长号是带回家的。非线程安全的只读是非常可悲的长号。
    【解决方案2】:

    可以以线程安全的方式访问底层 ndarray 中的数据,并自行承担修改风险。删除数据会很困难,因为更改 DataFrame 的大小通常需要创建一个新对象。我想在未来的某个时候改变这一点。

    【讨论】:

    猜你喜欢
    • 2011-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 2014-11-05
    • 1970-01-01
    相关资源
    最近更新 更多