- 科学计算
- 数据分析
【免费下载链接】numpy
The fundamental package for scientific computing with Python.
NumPy 2.4.4 是 2.4.x 分支上的一个补丁(patch)发布,主要修复 2.4.3 之后发现的一系列缺陷,其中最受关注的是终于彻底关闭 issue #30816——即 ARM 平台上 OpenBLAS 的线程问题。本文以官方发布说明为骨架,结合当前仓库源码与测试,逐项解析本次发布的修复内容、涉及的底层实现与验证方式,帮助读者理解这些改动对日常使用np.unique、ndarray.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_UINTP(npy_uintp的字节宽度,与size_t一致)作为编译期判断:== 8走 64 位 FNV-1a,否则走 32 位实现。两个实现分别基于经典初始化向量FNV1A_32_INIT = 0x811c9dc5与FNV1A_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_string(npy_fnv1a(value, num_chars * sizeof(T)))、hash_bytes(npy_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.add、np.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; - VSX2:
implies: VSX,参数-mcpu=power8;注释明确指出 "VSX2 is hardware baseline feature on ppc64le"; - VSX3:
implies: VSX2,参数-mcpu=power9,检测 cpu_vsx3.c,含VSX3_HALF_DOUBLE扩展检测; - VSX4:
implies: 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 运算 | #31049 | OpenBLAS 线程问题(#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)平台编译/运行 | #31079 | VSX 特性映射修正,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.
相关推荐
NumPy 2.0.2 补丁版本技术详解:19 项修复背后的源码级变更解析
NumPy 2.0.2 补丁版本技术详解:19 项修复背后的源码级变更解析 NumPy 2.0.2 是 2.0 系列发布后的第二个补丁版本(patch rele
科学计算数据分析NumPy 2.4.4 补丁版发布详解:哈希修复、ufunc 告警与 Python 3.14 兼容性改进
NumPy 2.4.4 补丁版发布详解:哈希修复、ufunc 告警与 Python 3.14 兼容性改进 导读 NumPy 2.4.4 是 2.4 系列的一个维
科学计算数据分析NumPy 2.3.2 补丁版发布详解:16 项修复全景拆解与源码级解析
NumPy 2.3.2 补丁版发布详解:16 项修复全景拆解与源码级解析 本指南以 NumPy 官方发布说明 doc/changelog/2.3.2 chang
科学计算数据分析
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考