线程安全#

NumPy 通过标准库中的 threading 模块支持在多线程环境中使用. 许多 NumPy 操作释放 GIL,因此与 Python 中的许多情况不同,可以通过利用 Python 中的多线程并行性来提高并行性能.

当每个工作线程拥有自己的数组或一组数组对象,并且线程之间没有直接共享数据时,最容易获得性能提升. 因为 NumPy 为许多底层操作释放 GIL,所以在底层代码中花费大部分时间的线程将并行运行.

可以在线程之间共享 NumPy 数组,但在修改多个线程之间共享的数组时,必须格外小心以避免创建线程安全问题. 如果两个线程同时读取和写入同一个数组,它们最多会产生不一致,竞争的结果,这些结果是不可重现的,更不用说正确的了. 还可以通过例如在另一个线程正在从中读取以计算 ufunc 操作时调整数组大小来使 Python 解释器崩溃.

将来,我们可能会向 ndarray 添加锁定,以使使用 NumPy 数组编写多线程算法更安全,但目前,我们建议专注于对线程之间共享的数组进行只读访问,或者如果您需要进行修改和多线程处理,则添加您自己的锁定.

请注意,不释放 GIL 的操作不会从使用 threading 模块中获得性能提升,而是可能更好地使用 multiprocessing . 特别是,对具有 dtype=object 的数组的操作不会释放 GIL.

无全局锁 Python#

在 2.1 版本加入.

从 NumPy 2.1 和 CPython 3.13 开始,NumPy 还实验性地支持禁用 GIL 的 python 运行时. 有关安装和使用无全局锁 Python 的更多信息,以及有关在依赖于 NumPy 的库中支持它的信息,请参阅 https://py-free-threading.github.io.

由于无全局锁 Python 没有全局解释器锁来序列化对 Python 对象的访问,因此线程有更多机会修改共享状态并创建线程安全问题. 除了上面提到的关于锁定 ndarray 对象的限制之外,这也意味着具有 dtype=object 的数组不受 GIL 保护,从而为 Python 对象创建了数据竞争,这些数据竞争在无全局锁 Python 之外是不可能的.