Tôi có một hàm C là mallocs() và điền vào một mảng phao nổi 2D. Nó "trả về" địa chỉ đó và kích thước của mảng. Chữ ký làTôi có thể bắt buộc một chiếc máy tính cáu kỉnh để sở hữu trí nhớ của nó không?
int get_array_c(float** addr, int* nrows, int* ncols);
Tôi muốn gọi nó từ Python, vì vậy tôi sử dụng ctypes.
import ctypes
mylib = ctypes.cdll.LoadLibrary('mylib.so')
get_array_c = mylib.get_array_c
Tôi chưa bao giờ tìm ra cách chỉ định loại đối số với ctypes. Tôi có xu hướng chỉ viết một wrapper python cho mỗi chức năng C tôi đang sử dụng, và chắc chắn rằng tôi nhận được các loại ngay trong wrapper. Mảng float là một ma trận theo thứ tự cột, và tôi muốn lấy nó như là một numpy.ndarray. Nhưng nó khá lớn, vì vậy tôi muốn sử dụng bộ nhớ được cấp phát bởi hàm C, không sao chép nó. (Tôi chỉ tìm thấy những thứ PyBuffer_FromMemory này trong câu trả lời StackOverflow này: https://stackoverflow.com/a/4355701/3691)
buffer_from_memory = ctypes.pythonapi.PyBuffer_FromMemory
buffer_from_memory.restype = ctypes.py_object
import numpy
def get_array_py():
nrows = ctypes.c_int()
ncols = ctypes.c_int()
addr_ptr = ctypes.POINTER(ctypes.c_float)()
get_array_c(ctypes.byref(addr_ptr), ctypes.byref(nrows), ctypes.byref(ncols))
buf = buffer_from_memory(addr_ptr, 4 * nrows * ncols)
return numpy.ndarray((nrows, ncols), dtype=numpy.float32, order='F',
buffer=buf)
này dường như để cho tôi một mảng với các giá trị đúng. Nhưng tôi khá chắc chắn đó là một rò rỉ bộ nhớ.
>>> a = get_array_py()
>>> a.flags.owndata
False
Mảng không sở hữu bộ nhớ. Đủ công bằng; theo mặc định, khi mảng được tạo từ bộ đệm, nó không nên. Nhưng trong trường hợp này nó nên. Khi mảng numpy bị xóa, tôi thực sự thích python để giải phóng bộ nhớ đệm cho tôi. Có vẻ như tôi có thể ép buộc nợ đúng là True, điều đó nên làm, nhưng owndata không thể giải quyết được.
giải pháp đạt yêu cầu:
Tận dụng tối gọi của get_array_py() chịu trách nhiệm giải phóng bộ nhớ. Đó là siêu gây phiền nhiễu; người gọi sẽ có thể xử lý mảng numpy này giống như bất kỳ mảng numpy khác.
Sao chép mảng ban đầu vào mảng mới (với bộ nhớ riêng, riêng) trong get_array_py, xóa mảng đầu tiên và giải phóng bộ nhớ bên trong get_array_py(). Trả lại bản sao thay vì mảng ban đầu. Điều này gây phiền nhiễu vì đó là bản sao bộ nhớ không cần thiết.
Có cách nào để làm những gì tôi muốn không? Tôi không thể sửa đổi các chức năng C chính nó, mặc dù tôi có thể thêm một chức năng C vào thư viện nếu đó là hữu ích.
Điều này nghe có vẻ như một thế giới của đau .. Tôi nghĩ rằng bạn đang yêu cầu [segfault địa ngục] (http://xkcd.com/371/) – wim
Tôi đã thử điều này là tốt mà không thành công bằng cách sử dụng ctypes. Một mô-đun mở rộng đầy đủ làm cho điều này có thể nhưng họ có nhiều việc phải viết hơn. –