我在内存中有一个碎片结构,我想将它作为一个连续的内存视图来访问它.有没有一种简单的方法可以做到这一点,还是应该实现自己的解决方案?
例如,考虑由记录组成的文件格式.每条记录都有一个固定长度的标题,用于指定记录内容的长度.更高级别的逻辑结构可能分布在多个记录中.如果它可以将它自己的碎片内存位置视为一个简单的连续字节数组,那么它将使更高级别的结构更容易实现.
更新:
似乎python在内部支持这种"分段"缓冲区类型,至少基于文档的这一部分.但这只是C API.
UPDATE2:
据我所知,引用的C API - 称为旧式缓冲区 - 可以满足我的需求,但现在已经弃用,并且在较新版本的Python(3.X)中不可用.新的缓冲协议 - 在PEP 3118中指定- 提供了一种表示缓冲区的新方法.这个API在大多数用例中更有用(其中,表示缓冲区在内存中不连续的用例),但不支持这个特定的用例,其中一维数组可以完全自由地布局(多个不同)记忆中的大小块.
关于cython中的内存视图,使用NumPy类型键入视图是否有任何优势,例如,如果我正在处理numpy浮点数组,np.float_t而不是简单地做double?
我应该cdef以同样的方式输入,例如
ctypedef np.float64_t np_float_t
...
@cython.profile(False)
@cython.wraparound(False)
@cython.boundscheck(False)
cdef np_float_t mean_1d(np_float_t [:] v) nogil:
cdef unsigned int n = v.shape[0]
cdef np_float_t n_sum = 0.
cdef Py_ssize_t i
for i in range(n):
n_sum += v[i]
return n_sum / n
Run Code Online (Sandbox Code Playgroud) 由于我发现内存视图方便快捷,我尝试避免在cython中创建NumPy数组并使用给定数组的视图.但是,有时无法避免,不能改变现有阵列而是创建新阵列.在上层函数中,这是不明显的,但在经常被称为子例程的情况下.考虑以下功能
#@cython.profile(False)
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)
cdef double [:] vec_eq(double [:] v1, int [:] v2, int cond):
''' Function output corresponds to v1[v2 == cond]'''
cdef unsigned int n = v1.shape[0]
cdef unsigned int n_ = 0
# Size of array to create
cdef size_t i
for i in range(n):
if v2[i] == cond:
n_ += 1
# Create array for selection
cdef double [:] s = np.empty(n_, dtype=np_float) # Slow line
# Copy selection to new array
n_ = 0 …Run Code Online (Sandbox Code Playgroud) 我无法将这个整数的内存视图传递给这个(相当简单的)函数.Python给了我这个错误:
ValueError: Buffer dtype mismatch, expected 'int' but got 'long'
Run Code Online (Sandbox Code Playgroud)
有人可以帮我理解发生了什么吗?搜索stackoverflow,似乎它与python如何解释类型以及C如何解释类型有关.
%%cython
def myfunction(int [:] y):
pass
# Python code
import numpy as np
y = np.array([0, 0, 1, 1])
myfunction(y)
Run Code Online (Sandbox Code Playgroud)
这ValueError从上面产生.
编辑:这是我发现的其他一些事情.
为了澄清,如果我声明y以下方式,则此错误仍然存在:
y = np.array([0, 0, 1, 1], dtype='int')
y = np.array([0, 0, 1, 1], dtype=np.int)
y = np.array([0, 0, 1, 1], dtype=np.int64)
Run Code Online (Sandbox Code Playgroud)
然而,它的工作原理,如果我宣布y与
y = np.array([0, 0, 1, 1], dtype=np.int32)
Run Code Online (Sandbox Code Playgroud)
有没有人想提出为什么会这样的建议?会np.int32在不同的电脑上投入工作吗?(我使用macbook pro retina,2013年.)
每当我为多维内存视图的一个切片分配单个值时,Cython似乎都会使用错误的步幅,除非该切片沿第一个维度。我在下面给出一个完整的例子:
# bug.py
import numpy as np
def bug():
#cdef int[:, ::1] a
a = 2*np.ones((2, 2), dtype=np.intc)
a[:, :1] = 1
print(np.asarray(a))
Run Code Online (Sandbox Code Playgroud)
如果我们在Python中运行此代码(例如python3 -c 'import bug; bug.bug()'),我们将得到
[[1 2]
[1 2]]
Run Code Online (Sandbox Code Playgroud)
按预期打印。现在,通过将文件重命名为bug.pyx,用Cython对其进行编译,并将以下文件保存在Makefile同一目录中,
# Makefile
python = python3
python_config = $(python)-config
CC = gcc
CFLAGS = $(shell $(python_config) --cflags) -fPIC
CFLAGS += $(shell $(python_config) --includes)
python_libdir = $(shell $(python) -c "import sysconfig; \
print(sysconfig.get_config_var('LIBDIR'));")
LDLIBS = -L$(python_libdir) -Wl,-rpath=$(python_libdir)
LDLIBS += $(shell $(python_config) --libs)
LDFLAGS …Run Code Online (Sandbox Code Playgroud) 是否有可能在cython中获得MemoryView的大小?理想情况下,我正在寻找像arr.shapenumpy 这样的东西.
我在Cython中编写了一个Python 2.7扩展模块. 如何创建一个实现新式缓冲区接口的Python对象,该接口包含C库提供给我的大块内存? 内存块只是一串字节,而不是结构或多维数组.我给了一个const void *指针和一个长度,以及一些指针保持有效的细节.
我无法复制内存 - 这会破坏我的应用程序的性能.
使用我可以简单使用的旧式缓冲区对象PyBuffer_FromMemory(),但我似乎无法找到一种类似的简单方法来生成新式缓冲区对象.
我是否必须创建自己的实现缓冲区接口的类?或者Cython提供了一种简单的方法吗?
我已经阅读了Cython文档中的Unicode和Passing Strings和Typed Memoryviews页面,但文档不精确且不够完整,并且没有类似于我想要做的示例.
这是我尝试过的(test.pyx):
from libc.stdlib cimport malloc
from libc.string cimport memcpy
## pretend that this function is in some C library and that it does
## something interesting. (this function is unrelated to the problem
## I'm experiencing -- this is just an example function that returns a
## chunk of memory that I want to wrap in …Run Code Online (Sandbox Code Playgroud) 我有一条蟒蛇memoryview指向一个bytes对象,我想在 cython 中对其执行一些处理。
我的问题是:
bytes对象不可写,cython 不允许从中构造类型化(cython)内存视图例子:
在蟒蛇中:
array = memoryview(b'abcdef')[3:]
Run Code Online (Sandbox Code Playgroud)
在cython中:
cdef char * my_ptr = &array[0] 无法编译消息: Cannot take address of Python variablecdef char[:] my_view = array 运行时失败并显示以下消息: BufferError: memoryview: underlying buffer is not writable怎么解决这个问题?
我遇到的问题是,在创建指向 mmap-s 的指针后,我无法在 Python 中正确关闭 mmap-s。我的用例是打开文件(通常是与硬件一起工作的 UIO 设备,但普通文件也会出现此问题),对它们进行内存映射,然后将它们用作 ctypes 结构的缓冲区。通常是数据结构或数组。一个最小的例子如下所示:
import ctypes as ct
import mmap
import os
fileno = os.open('/tmp/testfile', os.O_RDWR | os.O_SYNC)
map = mmap.mmap(fileno, 32768, flags=mmap.MAP_SHARED)
memory = (ct.c_uint32 * 8192).from_buffer(map)
# Use the memory object to do things here
del memory
map.close()
os.close(fileno)
Run Code Online (Sandbox Code Playgroud)
那时一切都很好。
但是,有时我需要调用一些也需要访问该内存的 C 库函数,因此我必须传入指向它们的指针。我使用以下方法创建该指针:
ptr = ct.cast(memory, ct.c_void_p)
Run Code Online (Sandbox Code Playgroud)
除了一件事之外,所有这些都运作良好。一旦我创建了这样的指针,我就无法再关闭内存映射。举个稍微扩展一下的例子:
import ctypes as ct
import mmap
import os
fileno = os.open('/tmp/testfile', os.O_RDWR | os.O_SYNC)
map = mmap.mmap(fileno, 32768, flags=mmap.MAP_SHARED)
memory = (ct.c_uint32 * 8192).from_buffer(map) …Run Code Online (Sandbox Code Playgroud) 我使用MPI(mpi4py)脚本(在单个节点上),该脚本可用于非常大的对象。为了让所有进程都可以访问该对象,我通过分发了该对象comm.bcast()。这会将对象复制到所有进程,并占用大量内存,尤其是在复制过程中。因此,我想共享诸如指针之类的东西,而不是对象本身。我发现一些memoryview有用的功能有助于增强流程中对象的工作。同样,对象的实际内存地址也可以通过memoryview对象字符串表示形式进行访问,并且可以这样分配:
from mpi4py import MPI
comm = MPI.COMM_WORLD
rank = comm.Get_rank()
if rank:
content_pointer = comm.bcast(root = 0)
print(rank, content_pointer)
else:
content = ''.join(['a' for i in range(100000000)]).encode()
mv = memoryview(content)
print(mv)
comm.bcast(str(mv).split()[-1][: -1], root = 0)
Run Code Online (Sandbox Code Playgroud)
打印:
<memory at 0x7f362a405048>
1 0x7f362a405048
2 0x7f362a405048
...
Run Code Online (Sandbox Code Playgroud)
这就是为什么我认为必须有一种方法可以在另一个过程中重构对象。但是,我在文档中找不到有关如何执行此操作的线索。
简而言之,我的问题是:是否可以在中同一节点上的进程之间共享对象mpi4py?
memoryview ×10
python ×9
cython ×7
numpy ×3
python-3.x ×3
pointers ×2
arrays ×1
ctypes ×1
memory ×1
mmap ×1
mpi ×1
mpi4py ×1
python-2.7 ×1
slice ×1
typing ×1