NumPy 2.4.4 补丁版本发布解析:OpenBLAS ARM 线程问题修复与源码级变更详解
2026/9/20 15:41:04 网站建设 项目流程
  • 科学计算
  • 数据分析

【免费下载链接】numpy

The fundamental package for scientific computing with Python.

项目地址:https://gitcode.com/gh_mirrors/nu/numpy
点击查看免费下载

NumPy 2.4.4 是 2.4.x 分支上的一个补丁(patch)发布,主要修复 2.4.3 之后发现的一系列缺陷,其中最受关注的是终于彻底关闭 issue #30816——即 ARM 平台上 OpenBLAS 的线程问题。本文以官方发布说明为骨架,结合当前仓库源码与测试,逐项解析本次发布的修复内容、涉及的底层实现与验证方式,帮助读者理解这些改动对日常使用np.uniquendarray.resize、ufunc 的where=参数等场景的实际影响。

发布概况

补丁定位与版本信息

NumPy 2.4.4 属于维护分支上的补丁发布,只包含 bug 修复(BUG)、文档说明(DOC)、测试修正(TST)与维护性改动(MAINT),不引入新特性。其核心定位在官方发布说明中写得很明确:

The NumPy 2.4.4 is a patch release that fixes bugs discovered after the 2.4.3 release. It should finally close issue #30816, the OpenBLAS threading problem on ARM.

即:修复 2.4.3 发布之后发现的问题,并最终关闭ARM 上 OpenBLAS 的线程问题(issue #30816)。这一点与 2.4.3 发布说明中"最显眼的修复是 OpenBLAS 在 ARM 上的线程问题"相衔接,说明该问题在 2.4.3 中引入了回归测试,在 2.4.4 中彻底收尾。

Python 版本支持范围

本版本支持Python 3.11–3.14。当前仓库主线的 pyproject.toml 中requires-python = ">=3.12",且Programming Language :: Python :: 3.12/3.13/3.14元数据齐全——2.4.4 相比主线还额外保留了 3.11 的兼容,是面向下游发行版的关键维护版本。

贡献者与合并 PR 规模

  • 8 位贡献者,其中 3 位(带+号)为首次向 NumPy 提交补丁:Daniel Haag、Denis Prokopenko、Harshith J;其余为 Charles Harris、Koki Watanabe、Marten van Kerkwijk、Matti Picus、Nathan Goldbaum。
  • 本版本共合并7 个 pull request,涵盖维护准备、回归测试、三处 bug 修复、一处文档补充与一处 SWIG 接口维护。

七个合并 PR 逐项解析

1. MAINT: Prepare 2.4.x for further development(#30978)

这是补丁分支的例行"维护准备"改动:在发布 2.4.3 之后,将 2.4.x 分支上的开发版本号前移(bump version),为后续 2.4.4 及后续补丁的构建、文档与安装包做准备。这类改动通常只影响version.py等元数据文件,不触碰任何运行时逻辑。

2. BUG: Add test to reproduce problem described in #30816(#31049,对应 #30818)

这是围绕OpenBLAS ARM 线程问题的回归测试。问题背景:在 ARM(aarch64)平台上,当 NumPy 链接的多线程 OpenBLAS 在特定场景(如np.linalg中的分块运算)下会因线程池配置或竞态出现挂起/异常,即 issue #30816。2.4.3 的发布说明已提及该线程修复,2.4.4 的这项工作是把复现该问题的测试补充进测试套件,确保问题不会再次回归——这正是"should finally close"的验证闭环:修复 + 可复现测试双保险。

由于该问题位于第三方 BLAS 库(OpenBLAS)的线程层,仓库内的 C/C++ 源码并不直接包含其修复,但测试的存在保证了发行版构建时(numpy/linalg相关测试)能够捕获 ARM 上的线程回归。

3. BUG: fix FNV-1a 64-bit selection by using NPY_SIZEOF_UINTP(#31052,对应 #31035)

这是本版本中纯核心源码修复中最典型的一处,直接影响np.unique等依赖哈希表的路径。

问题本质:FNV-1a 哈希在需要返回size_t(指针宽度)哈希值时,应根据平台的字长选择 32 位还是 64 位实现。旧代码可能在判断条件上误用了与size_t宽度不一致的宏,导致在特定平台上哈希宽度选择错误(例如在 64 位平台回退到 32 位哈希),进而造成哈希碰撞率上升、np.unique等去重/排序路径性能退化甚至行为异常。

修复后的实现:查看当前仓库 numpy/_core/src/multiarray/fnv.c:

size_t npy_fnv1a(const void *buf, size_t len) { #if NPY_SIZEOF_UINTP == 8 return (size_t)npy_fnv1a_64(buf, len, FNV1A_64_INIT); #else /* NPY_SIZEOF_UINTP == 4 */ return (size_t)npy_fnv1a_32(buf, len, FNV1A_32_INIT); #endif }

关键点在于使用NPY_SIZEOF_UINTPnpy_uintp的字节宽度,与size_t一致)作为编译期判断:== 8走 64 位 FNV-1a,否则走 32 位实现。两个实现分别基于经典初始化向量FNV1A_32_INIT = 0x811c9dc5FNV1A_64_INIT = 0xcbf29ce484222325ULL,并以移位加法展开魔数乘法(如hval += (hval<<1) + (hval<<4) + (hval<<5) + (hval<<7) + (hval<<8) + (hval<<40)等价于乘0x100000001b3ULL),见 fnv.c。

调用链与影响面npy_fnv1a在 numpy/_core/src/multiarray/unique.cpp 中被用作np.unique哈希表的核心哈希函数:

template <typename T> size_t hash_integer(const T *value, npy_bool equal_nan) { return npy_fnv1a(reinterpret_cast<const unsigned char*>(value), sizeof(T)); }

同文件中的hash_complex(对复数拆分为实部/虚部规范后哈希)、hash_stringnpy_fnv1a(value, num_chars * sizeof(T)))、hash_bytesnpy_fnv1a(value->buf, value->size * sizeof(char)))等路径全部经由npy_fnv1a,因此本次修复统一修正了np.unique在整数、复数、字符串、字节串等多 dtype 上的哈希宽度选择。该函数对外接口声明于 fnv.h,并通过 meson.build 编入multiarray模块。

4. BUG: avoid warning on ufunc with where=True and no output(#31053)

场景:在调用 ufunc(如np.addnp.multiply)时传入where=True不提供out参数,旧版本会触发一个不必要的警告。修复目标是:where=True作为"全选"语义时,若用户未提供输出数组,应当安静地按正常全量计算处理,而不是告警。

底层依据:从源码看,where=掩码在 numpy/_core/src/umath/ufunc_object.c 经由_wheremask_converter转为布尔数组,进入PyUFunc_GenericFunctionInternal后走"masked inner loop"分支——此时输出操作数会被打上NPY_ITER_WRITEMASKED标志(ufunc_object.c),而where=None/True这类全量掩码在无out时本无必要触发警告。修复后该路径行为与不带where的调用保持一致,消除了无意义告警对 CI 与用户脚本的干扰。

5. DOC: document caveats of ndarray.resize on 3.14 and newer(#31058)

背景:Python 3.14 修改了函数局部变量的引用计数(reference counting)语义,导致ndarray.resize内置的refcheck(引用检查)机制可能产生误报——即数组明明只被一个变量引用,却被判定"可能被其他对象引用"而抛出ValueError

文档补充内容:本次 PR 在ndarray.resize的文档中明确记录该注意事项:在 Python 3.14 及以上版本中,若resize因引用检查误报而失败,可通过显式传入refcheck=False规避(前提是确认数组确实是唯一引用)。

源码佐证:查看当前仓库 numpy/_core/src/multiarray/shape.c 中的实现,已经内建了针对 3.14 的差异化逻辑:

if (refcheck) { #if PY_VERSION_HEX >= 0x030E00B0 // Python 3.14 changed reference counting semantics for function- // local variables. There is no way to tell if the calling function // has been optimized (because it might be implemented in C or Cython) // // Instead, warn if the refcount is exactly 2 that this might be a // false positive if (!PyUnstable_Object_IsUniquelyReferenced((PyObject *)self)) { if (Py_REFCNT(self) == 2) { PyErr_SetString( PyExc_ValueError, "cannot resize an array that may be referenced " "by another object.\n" "It is possible that this is a false positive.\n" "If you are sure that the array is uniquely referenced, " "set refcheck=False."); return -1; } } #else if (Py_REFCNT(self) > 2) { #endif ... } }

可见在PY_VERSION_HEX >= 0x030E00B0(即 Python 3.14)分支,错误信息中明确提示 "It is possible that this is a false positive" 并引导用户 "set refcheck=False"——这正是 #31058 文档化内容的代码端落地。resize的入口array_resize(methods.c)解析refcheck关键字后调用PyArray_Resize_int,其整体流程(单段内存校验、尺寸溢出检测、OWNDATA校验、重新分配与零填充)见 shape.c。

测试验证:仓库测试 numpy/_core/tests/test_multiarray.py 中的test_check_reference_module_scope专门覆盖了 3.14 下的这一行为:

@pytest.mark.skipif( not HAS_SUBPROCESSES, reason="platform cannot start subprocesses" ) def test_check_reference_module_scope(self): code = textwrap.dedent(""" import numpy as np # See gh-30991 a = np.array([[0, 1], [2, 3]], order='C') a.resize((2, 1)) """) try: subprocess.check_output([sys.executable, "-c", code], stderr=subprocess.STDOUT, text=True) except subprocess.CalledProcessError as e: assert sys.version_info >= (3, 14) assert "ValueError" in e.stdout assert "It is possible that this is a false positive." in e.stdout else: if sys.version_info >= (3, 14): raise AssertionError("Unexpected success of resize refcheck")

该测试精确断言:3.14 下报错信息必须包含 "It is possible that this is a false positive.",否则视为测试失败。同类测试还有test_check_reference(test_multiarray.py)与test_check_reference_2(test_multiarray.py),分别验证函数作用域与一般共享引用场景。

6. TST: fix POWER VSX feature mapping(#31079,对应 #30801)

问题:在 PowerPC(ppc64/ppc64le)平台上,NumPy 的 CPU 特性检测框架对 VSX(Vector Scalar eXtension,POWER 平台的 SIMD 指令集扩展)的特性映射存在错误(#30801),可能导致编译期特性匹配不正确,进而影响 SIMD 内核的选用或误判。

修复内容:修正测试/检测逻辑中 VSX 系列特性的映射关系。当前仓库 meson_cpu/ppc64/meson.build 中可见完整的 VSX 特性层级:

  • VSX:基础特性,编译参数-mvsx,检测代码位于 numpy/_core/src/_simd/checks/cpu_vsx.c;
  • VSX2implies: VSX,参数-mcpu=power8;注释明确指出 "VSX2 is hardware baseline feature on ppc64le";
  • VSX3implies: VSX2,参数-mcpu=power9,检测 cpu_vsx3.c,含VSX3_HALF_DOUBLE扩展检测;
  • VSX4implies: VSX3,参数-mcpu=power10,检测 cpu_vsx4.c。

该 PR 正是修正这一层层implies链与编译参数匹配规则(match: '.*vsx'/'.*(?:mcpu=|vsx).*')中的缺陷,保证 meson 构建时对 POWER 平台 CPU 特性的正确探测与 SIMD 路径选择。

7. MAINT: numpy.i: Replace deprecatedsprintfwithsnprintf(#31084)

问题:NumPy 提供的 SWIG 接口文件 tools/swig/numpy.i 中使用了已被标记废弃的sprintf,在新编译环境下会产生弃用告警,且缺乏缓冲区长度保护。

修复内容:将sprintf全部替换为带长度上限的snprintf。当前仓库中已能直接看到替换后的代码,例如生成形状字符串的片段(numpy.i):

snprintf(s, sizeof(s), "%d, ", exact_dimensions[i]); ... snprintf(s, sizeof(s), " or %d", exact_dimensions[n-1]); snprintf(s, sizeof(s), "%ld,", (long int)size[i]);

这一改动消除了numpy.i生成 C 代码时的弃用告警,并借助sizeof(s)参数防止越界写入,属于面向 SWIG 绑定用户(numpy.i用于为 C/C++ 库生成 NumPy 感知的 Python 绑定)的低风险维护性修复。

对用户的实际影响与升级建议

综合来看,NumPy 2.4.4 对多数用户属于低风险升级,但以下几类用户应优先关注:

场景相关 PR用户可见影响
ARM/aarch64 平台使用np.linalg等 BLAS 运算#31049OpenBLAS 线程问题(#30816)最终关闭,配合回归测试防止复发
大量使用np.unique(含复数、字符串 dtype)#31052哈希宽度选择修正,64 位平台恢复 64 位 FNV-1a,降低碰撞、保证正确性
ufunc 传where=True且省略out#31053不再产生不必要的告警
Python 3.14 下调用ndarray.resize#31058文档明确refcheck误报注意事项,可用refcheck=False规避
POWER(ppc64le)平台编译/运行#31079VSX 特性映射修正,SIMD 路径选择更准确
使用 SWIG +numpy.i构建绑定#31084消除sprintf弃用告警,提升生成代码的安全性

对于 Python 3.14 用户,若在调用a.resize(new_shape)时遇到报错信息中包含 "It is possible that this is a false positive.",说明命中了 3.14 引用计数语义变更带来的误报,可在确认数组唯一引用后按提示改为a.resize(new_shape, refcheck=False)

总结

NumPy 2.4.4 虽然只有 7 个 PR,但覆盖面横跨平台线程(ARM OpenBLAS)、核心哈希(FNV-1a 字宽选择)、ufunc 告警、Python 3.14 兼容性文档、POWER SIMD 特性映射与 SWIG 接口安全六个方向,且每一项都有对应的源码实现或测试闭环支撑:

  • FNV-1a 修复可从 fnv.c 的NPY_SIZEOF_UINTP分支直接验证;
  • resize 的 3.14 行为可从 shape.c 与 test_multiarray.py 双重确认;
  • VSX 映射可从 meson_cpu/ppc64/meson.build 核对。

对于在 ARM、POWER 等非 x86 平台部署 NumPy 的用户,2.4.4 是值得跟进的一个维护版本;对于 x86 通用用户,本次发布也通过np.unique哈希与 ufunc 告警修复提升了稳定性与信噪比。

  • 科学计算
  • 数据分析

【免费下载链接】numpy

The fundamental package for scientific computing with Python.

项目地址:https://gitcode.com/gh_mirrors/nu/numpy
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询