Ich schrieb eine Funktion, die numpy Array in C-Code mit CFFI übergibt. Es verwendet das Pufferprotokoll und die Speicheransicht, um die Daten effizient zu übertragen, ohne sie zu kopieren. Dies bedeutet jedoch, dass Sie C-zusammenhängende Arrays übergeben und sicherstellen müssen, dass Sie die richtigen Typen verwenden. Numpy bietet eine Funktion numpy.ascontiguous,
, die dies tut. Also iteriere ich über die Argumente und wende diese Funktion an. Die folgende Implementierung funktioniert und kann von allgemeinem Interesse sein. Es ist jedoch langsam, wenn es so oft aufgerufen wird. (Irgendwelche allgemeinen Bemerkungen, wie man es beschleunigt, wäre hilfreich.)Generator Verständnis und Liste Verständnis iterieren anders
Jedoch ist die tatsächliche Frage, wenn Sie das erste Listenverstehen mit einem Generatorverstehen ersetzen, oder wenn Sie den Code so refaktorieren, dass np.ascontigous
in genannt wird zweitens zeigen die in den C-Code überführten Zeiger nicht mehr auf den Anfang des numply-Arrays. Ich denke, dass es nicht angerufen wird. Ich wiederhole das Verständnis und verwende nur die Rückgabewerte, warum würde die Verwendung eines Listenverständnisses oder eines Generatorverständnisses irgendetwas verändern?
def cffi_wrap(cffi_func, ndarray_params, pod_params, return_shapes=None):
"""
Wraps a cffi function to allow it to be called on numpy arrays.
It uss the numpy buffer protocol and and the cffi buffer protocol to pass the
numpy array into the c function without copying any of the parameters.
You will need to pass dimensions into the C function, which you can do using
the pod_params.
Parameters
----------
cffi_func : c function
This is a c function declared using cffi. It must take double pointers and
plain old data types. The arguments must be in the form of numpy arrays,
plain old data types, and then the returned numpy arrays.
ndarray_params : iterable of ndarrays
The numpy arrays to pass into the function.
pod_params : tuple of plain old data
This plain old data objects to pass in. This may include for example
dimensions.
return_shapes : iterable of tuples of positive ints
The shapes of the returned objects.
Returns
-------
return_vals : ndarrays of doubles.
The objects to be calculated by the cffi_func.
"""
arr_param_buffers = [np.ascontiguousarray(param, np.float64)
if np.issubdtype(param.dtype, np.float)
else np.ascontiguousarray(param, np.intc) for param in ndarray_params]
arr_param_ptrs = [ffi.cast("double *", ffi.from_buffer(memoryview(param)))
if np.issubdtype(param.dtype, np.float)
else ffi.cast("int *", ffi.from_buffer(memoryview(param)))
for param in arr_param_buffers]
if return_shapes is not None:
return_vals_ptrs = tuple(ffi.new("double[" + str(np.prod(shape)) + "]")
for shape in return_shapes)
returned_val = cffi_func(*arr_param_ptrs, *pod_params, *return_vals_ptrs)
return_vals = tuple(np.frombuffer(ffi.buffer(
return_val))[:np.prod(shape)].reshape(shape)
for shape, return_val in zip(return_shapes, return_vals_ptrs))
else:
returned_val = cffi_func(*arr_param_ptrs, *pod_params)
return_vals = None
if returned_val is not None and return_vals is not None:
return_vals = return_vals + (returned_val,)
elif return_vals is None:
return_vals = (returned_val,)
if len(return_vals) == 1:
return return_vals[0]
else:
return return_vals
Beachten Sie, dass, obwohl Sie eine Runde des Kopierens vermeiden können, indem Sie auf das Pufferprotokoll angewiesen sind, keinen besonderen Grund zu der Annahme, dass "np.ascontigoarray()" die Daten nicht kopieren würde. Das könnte ein Grund sein, warum der Code langsam ist. Sie können bessere Ergebnisse erzielen, wenn Sie die numpigen Array-Objekte unverändert übergeben und die C-API von Numpy für den Zugriff auf die C-Seite verwenden. Ich denke, das spielt nicht so gut mit cffi, aber es ist etwas zu beachten. –
Ich denke, das ist möglich. Ich denke, obwohl ich denke, könnte falsch sein, dass np.ascontinuous nur kopiert, wenn es muss. Die meiste Zeit sollte es nichts tun. Wenn Sie den Code profilieren, ist der langsame Teil np.issubdtype() und das Casting. Dem Casting kann ich nicht wirklich entkommen. Die Frage kam von der Tatsache, dass ich np.issubdtype() nicht zweimal aufrufen sollte. – sangrey
"Es funktioniert nicht mehr" - können Sie genauer sein? Wie scheitert es? –