检查内存视图上的文档:
memoryview对象允许Python代码访问支持缓冲区协议的对象的内部数据而无需复制.
class memoryview(obj)
创建一个引用obj的内存视图.obj必须支持缓冲协议.支持缓冲区协议的内置对象包括bytes和bytearray.
然后我们给出示例代码:
>>> v = memoryview(b'abcefg')
>>> v[1]
98
>>> v[-1]
103
>>> v[1:4]
<memory at 0x7f3ddc9f4350>
>>> bytes(v[1:4])
b'bce'
Run Code Online (Sandbox Code Playgroud)
报价结束,现在让我们仔细看看:
>>> b = b'long bytes stream'
>>> b.startswith(b'long')
True
>>> v = memoryview(b)
>>> vsub = v[5:]
>>> vsub.startswith(b'bytes')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'memoryview' object has no attribute 'startswith'
>>> bytes(vsub).startswith(b'bytes')
True
>>>
Run Code Online (Sandbox Code Playgroud)
所以我从上面收集的内容:
我们创建一个memoryview对象来公开缓冲区对象的内部数据而不进行复制,但是,为了对对象做任何有用的事情(通过调用对象提供的方法),我们必须创建一个副本!
当我们有一个大对象时,通常需要memoryview(或旧的缓冲区对象),并且切片也可能很大.如果我们正在制作大切片,或者制作小切片但需要很多次,则需要提高效率.
有了上述方案,我看不出它对两种情况都有用,除非有人能向我解释我在这里缺少的东西.
EDIT1:
我们有大量数据,我们希望通过从头到尾推进它来处理它,例如从字符串缓冲区的开头提取标记,直到缓冲区被消耗.在C语言中,这是推进指针通过缓冲区,指针可以传递给任何期望缓冲区类型的函数.如何在python中完成类似的事情?
人们建议使用变通方法,例如许多字符串和正则表达式函数采用可用于模拟推进指针的位置参数.这有两个问题:首先是一个解决方法,你被迫改变你的编码风格来克服缺点,第二个:并非所有函数都有位置参数,例如正则表达式函数和startswithdo,encode()/ …
我正在将Cython内存视图转换为numpy数组(以便能够在纯Python代码中使用它):
from libc.stdlib cimport realloc
cimport numpy as np
DTYPE = np.float64
ctypedef np.float64_t DTYPE_t
cpdef np.ndarray[DTYPE_t] compute(DTYPE_t[:,::1] data):
cdef unsigned int Nchannels = data.shape[0]
cdef unsigned int Ndata = data.shape[1]
cdef DTYPE_t* output = NULL
cdef DTYPE_t[::1] mv
output = <DTYPE_t*>realloc(output, Ndata*sizeof(output))
if not output:
raise MemoryError()
mv = <DTYPE_t[:Ndata]>output
mv[10:Ndata-10] = 0.0
# various calculations...
return np.asarray(mv, dtype=DTYPE, order='C')
Run Code Online (Sandbox Code Playgroud)
它编译,但编译器给出以下警告:
/Users/vlad/anaconda/lib/python2.7/site-packages/numpy/core/include
/nump/npy_1_7_deprecated_api.h:15:2: warning:
"Using deprecated NumPy API, disable it by #defining NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION" [-W#warnings]
Run Code Online (Sandbox Code Playgroud)
我在setup.py中添加了建议的指令:
from distutils.core import …Run Code Online (Sandbox Code Playgroud) memoryview的完整描述可以在这里找到:
创建一个
memoryview引用obj.obj必须支持缓冲协议.支持缓冲协议的内置对象包括bytes和bytearray.A
memoryview具有元素的概念,元素是由始发对象obj处理的原子存储单元.对于许多简单类型,例如bytes和bytearray,元素是单个字节,但是其他类型array.array可能具有更大的元素.
Pythons memoryview不支持datetime64或timedelta.好.但是,当我尝试创建一个memoryview包含一个datetime64或的结构化数组时timedelta,它似乎可以工作...... 除非我将它分配给一个变量!
In [19]: memoryview(zeros(10, dtype=[("A", "m8[s]")]))
Out[19]: <memory at 0x7f1d455d6048>
In [20]: x = memoryview(zeros(10, dtype=[("A", "m8[s]")]))
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
ValueError: cannot include dtype 'm' in a buffer
In [21]: x = _19
In [22]: x
Out[22]: <memory at 0x7f1d455d6048>
Run Code Online (Sandbox Code Playgroud)
这严重挑战了我对Python基本工作方式的理解.怎么能f()和x = f()不同,考虑到(1)IPythons REPL分配输出到_19反正,和(2)的函数/类memoryview没有知道什么是来电者会用它的输出做的呢?
我正在运行Python 3.4.1上的代码,numpy 1.10.0.dev + fbcc24f,在Linux 2.6.32-431.23.3.el6.x86_64,Scientific Linux发行版6.6上.
编辑
在Python …
python numpy read-eval-print-loop memoryview structured-array
如何在cython中将类型化的内存视图转换为NumPy数组?文档有
cimport numpy as np
import numpy as np
numpy_array = np.asarray(<np.int32_t[:10, :10]> my_pointer)
Run Code Online (Sandbox Code Playgroud)
我把它当作我的情况
np.asarray(<np.float_t[:, :]> my_memview)
Run Code Online (Sandbox Code Playgroud)
使用这个编译器告诉我:
Can only create cython.array from pointer or array
Run Code Online (Sandbox Code Playgroud)
复制与否并非如此具有决定性.我找不到任何帮助.
Cython 文档很好地解释了它们允许的内容,如何声明它们以及如何使用它们.
但是,我仍然不清楚他们到底是什么.例如,来自numpy数组的简单赋值如下:
my_arr = np.empty(10, np.int32)
cdef int [:] new_arr = my_arr
Run Code Online (Sandbox Code Playgroud)
可以使访问/分配my_arr更快.
幕后发生了什么?Numpy应该已经以连续的方式在内存中分配元素了,那么内存视图的处理是什么?显然不是那么多,实际上numpy数组的memoryview赋值new_arr应该相当于
cdef np.ndarray[np.int32_t, ndim=1] new_arr = np.empty(10, np.int32)
Run Code Online (Sandbox Code Playgroud)
在速度方面.但是,内存视图被认为比numpy数组缓冲区更通用; 你能举一个简单的例子,其中添加的"概括"是重要/有趣的吗?
此外,如果我已经分配了一个指针以使事情尽可能快,那么将它转换为类型化的内存视图有什么好处?(这个问题的答案可能与上面的问题相同)
cdef int *my_arr = <int *> malloc(N * sizeof(int))
cdef int[:] new_arr = <int[:N]>my_arr
Run Code Online (Sandbox Code Playgroud) 我如何编写一个Cython函数,它将一个字节串对象(一个普通字符串,一个bytearray或另一个跟在缓冲区协议下的对象)作为一个类型化的内存视图?
根据Unicode和Passing Strings Cython教程页面,以下内容应该有效:
cpdef object printbuf(unsigned char[:] buf):
chars = [chr(x) for x in buf]
print repr(''.join(chars))
Run Code Online (Sandbox Code Playgroud)
它适用于bytearrays和其他可写缓冲区:
$ python -c 'import test; test.printbuf(bytearray("test\0ing"))'
'test\x00ing'
Run Code Online (Sandbox Code Playgroud)
但它不适用于普通字符串和其他只读缓冲区对象:
$ python -c 'import test; test.printbuf("test\0ing")'
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "test.pyx", line 1, in test.printbuf (test.c:1417)
File "stringsource", line 614, in View.MemoryView.memoryview_cwrapper (test.c:6795)
File "stringsource", line 321, in View.MemoryView.memoryview.__cinit__ (test.c:3341)
BufferError: Object is not writable.
Run Code Online (Sandbox Code Playgroud)
查看生成的C代码,Cython总是将PyBUF_WRITABLE标志传递给PyObject_GetBuffer(),这解释了异常. …
考虑这个虚拟的Cython代码:
#!python
#cython: boundscheck=False
#cython: wraparound=False
#cython: initializedcheck=False
#cython: cdivision=True
#cython: nonecheck=False
import numpy as np
# iterator function
cdef double[:] f(double[:] data):
data[0] *= 1.01
data[1] *= 1.02
return data
# looping function
cdef double[:] _call_me(int bignumber, double[:] data):
cdef int ii
for ii in range(bignumber):
data = f(data)
return data
# helper function to allow calls from Python
def call_me(bignumber):
cdef double[:] data = np.ones(2)
return _call_me(bignumber, data)
Run Code Online (Sandbox Code Playgroud)
现在,如果我对此进行了一次cython -a,它会以黄色显示返回语句.我在一个性能非常关键的程序中做了类似的事情,根据分析,这实际上减慢了我的代码速度.那么,为什么cython需要python用于这些返回语句?带注释的文件提供了一个提示:
PyErr_SetString(PyExc_TypeError,"Memoryview return value is not initialized"); …Run Code Online (Sandbox Code Playgroud) Python 2.7 为缓冲区和内存视图对象引入了一个新的API.
我阅读了关于它们的文档,我认为我得到了基本的概念(以原始形式访问对象的内部数据而不复制它,我想这意味着"更快,更少内存的"获取对象数据的方式),但要真正理解文档,读者应该具备超越我所拥有的C知识.
如果有人愿意花时间,我将非常感激:
在Cython代码中,我可以分配一些内存并将其包装在内存视图中,例如:
cdef double* ptr
cdef double[::1] view
ptr = <double*> PyMem_Malloc(N*sizeof('double'))
view = <double[:N]> ptr
Run Code Online (Sandbox Code Playgroud)
如果现在我使用释放内存PyMem_Free(ptr),则尝试访问元素之类ptr[i]的错误将导致错误。但是,我可以安全地尝试访问view[i](尽管它不会返回原始数据)。
我的问题是:仅释放指针总是安全吗?是否以某种方式通知内存视图对象已释放内存,还是应该以某种方式手动删除视图?此外,即使内存视图引用了内存,也可以保证释放内存吗?
memoryview ×10
python ×10
cython ×6
numpy ×4
arrays ×2
python-2.7 ×2
buffer ×1
c ×1
free ×1
memory ×1
python-2.x ×1
python-3.x ×1