线程安全#

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

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

在线程之间共享 NumPy 数组是可能的,但在多个线程之间共享并变异数组时,必须极其小心以避免创建线程安全问题.如果两个线程同时从同一个数组读取和写入,它们最好的情况下会产生不一致、不可重现的结果,更不用说正确了.例如,通过在另一个线程读取数组以计算 ufunc 操作时调整数组大小,也可能导致 Python 解释器崩溃.

在未来,我们可能会为 ndarray 添加锁定功能,以使使用 NumPy 数组编写多线程算法更安全,但目前我们建议专注于线程之间共享数组的只读访问,或者如果您需要变异和多线程,请添加自己的锁定.

请注意,那些*不*释放GIL的操作将不会从使用`threading`模块中获得性能提升,相反,使用`multiprocessing`可能会更好.特别是,对``dtype=object``的数组的操作不会释放GIL.

Free-threaded Python#

在 2.1 版本加入.

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

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