python numpy tolist() 增加了多少开销?
Posted
技术标签:
【中文标题】python numpy tolist() 增加了多少开销?【英文标题】:How much overhead does python numpy tolist() add? 【发布时间】:2016-09-16 03:09:37 【问题描述】:我正在使用一个 python 程序,它使用 numpy 数组作为数组的标准数据类型。对于繁重的计算,我将数组传递给 C++ 库。为此,我使用pybind。但是,我需要使用 python list
。我通过 numpy
数组和 list
进行转换:
NativeSolver.vector_add(array1.tolist(), array2.tolist(), ...)
这种转换会产生多少开销?我希望它不会创建一个全新的副本。 Numpy 参考说:
ndarray.tolist()
将数组数据的副本作为(嵌套)Python 列表返回。数据项 被转换为最接近的兼容 Python 类型。
【问题讨论】:
我在pybind
github 和文档中找到了对缓冲区协议和numpy 的引用。
【参考方案1】:
很多。对于简单的内置类型,您可以在对象上使用sys.getsizeof
来确定与该对象关联的内存开销(对于容器,这不包括存储在其中的值,仅包括用于存储它们的指针)。
例如,100 个较小的 int
s 的 list
(但大于 256 以避免小的 int
缓存)是(在我的 3.5.1 Windows x64 安装上):
>>> sys.getsizeof([0] * 100) + sys.getsizeof(0) * 100
3264
或大约需要 3 KB 的内存。如果这些相同的值存储在 int32
s 的 numpy
array
中,每个数字没有 Python 对象,也没有每个对象指针,那么大小将下降到大约 100 * 4(加上另外几十个字节,对于array
对象开销本身),低于 500 字节。每个额外的小 int
的增量成本是对象的 24 个字节(尽管如果它在小的 int 缓存中对于从 -5 到 256 IIRC 的值是免费的),并且在 list
中存储 8 个字节,32字节总数,而 C 级别类型为 4,大约是存储需求的 8 倍(而且您仍在存储原始对象)。
如果你有足够的内存来处理它,那就这样吧。但除此之外,您可能会尝试查看允许您传入缓冲区协议支持对象的包装(numpy.array
、Py3 上的array.array
、通过 memoryview 切片分配填充的ctypes
数组等),因此转换为 Python 级别类型是不需要。
【讨论】:
【参考方案2】:是的,它将是新副本。数组的数据布局与列表的数据布局非常不同。
数组具有形状和步幅等属性,以及包含元素的一维数据缓冲区 - 只是一组连续的字节。是其他属性和代码将它们视为浮点数、整数、字符串、1d、2d 等。
列表是指针的缓冲区,每个指针都指向内存中其他位置的对象。它可能指向一个数字、一个字符串或另一个列表。它不会指向数组的数据缓冲区或其中的元素。
有 numpy 数组与编译代码和 C 数组使用数组数据缓冲区的接口。 cython
是常用的。还有一个关于 numpy 的 C API 的完整文档部分。我对pbind
一无所知。如果它需要一个列表界面,它可能不是最好的。
当我使用tolist()
完成timeit
测试时,它似乎并没有那么昂贵。
=========================
但是查看pybind11
github,我发现了许多对numpy
的引用,而这个
http://pybind11.readthedocs.io/en/latest/advanced.html#numpy-support
文档页面。它支持缓冲区协议和 numpy 数组。因此,您不必执行tolist
步骤。
#include <pybind11/numpy.h>
void f(py::array_t<double> array);
【讨论】:
我知道。我不想为某些 pybind11 数据类型放弃 STL 数据类型。我现在结束了使用 SWIG。在我看来,SWIG 是唯一允许 python 和 c++ 文件尽可能保持原样的包装器。以上是关于python numpy tolist() 增加了多少开销?的主要内容,如果未能解决你的问题,请参考以下文章
Python\Numpy:将数组与 NAN 进行比较 [重复]