生成器理解和列表理解迭代方式不同。

2024-05-16 10:36:15 发布

您现在位置:Python中文网/ 问答频道 /正文

我编写了一个函数,使用CFFI将numpy数组传递到C代码中。它利用缓冲协议和memoryview在不复制数据的情况下高效地传递数据。但是,这意味着您需要传递C连续数组,并确保使用正确的类型。Numpy提供了一个函数numpy.ascontiguous,,它实现了这一点。所以我迭代这些参数,并应用这个函数。下面的实现是可行的,并且可能具有普遍意义。然而,考虑到它被调用的次数,它是缓慢的。(任何关于如何加速的一般性评论都会有所帮助。)

然而,实际的问题是,当您用生成器理解替换第一个列表理解时,或者如果您重构代码以便在第二个列表理解中调用np.ascontigous,那么传递到C代码中的指针将不再指向numpy数组的开始。我想它不会被叫来的。我在迭代理解,只使用返回值,为什么使用列表理解或生成器理解会改变什么?你知道吗

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

Tags: ofthetonumpynonereturnparamnp
1条回答
网友
1楼 · 发布于 2024-05-16 10:36:15

我只是猜测,但是错误可能来自keepalives:使用arr_param_buffers列表理解,就像在您发布的代码中一样,那么只要这个局部变量存在(即在cffi\u wrap()的整个持续时间内),所有创建的numpy数组都是活动的。这允许您在下一行执行ffi.from_buffer(memoryview(...)),并确保它们都是指向有效数据的指针。你知道吗

如果用生成器表达式替换arr_param_buffers,它将逐个生成新的numpy数组,对它们调用ffi.from_buffer(memoryview(param)),然后将它们丢弃。据我所知,ffi.from_buffer(x)返回一个应该使x保持活动的对象,但是x == memoryview(nd)本身可能不会使numpy数组nd保持活动。你知道吗

相关问题 更多 >