簡體   English   中英

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

[英]Generator Comprehension and List Comprehension iterate differently

我編寫了一個函數,該函數使用 CFFI 將 numpy 數組傳遞到 C 代碼中。 它利用緩沖區協議和內存視圖來高效地傳遞數據而無需復制它。 但是,這意味着您需要傳遞 C 連續數組並確保使用正確的類型。 Numpy 提供了一個函數numpy.ascontiguous,它可以做到這一點。 所以我迭代參數,並應用這個函數。 下面的實現有效,並且可能引起普遍關注。 但是,考慮到它被調用的次數,它很慢。 (關於如何加快速度的任何一般性評論都會有所幫助。)

然而,實際的問題是,當您用生成器np.ascontigous替換第一個列表np.ascontigous ,或者如果您重構代碼以便在第二個中調用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

我只是在猜測,但錯誤可能來自 keepalives:使用arr_param_buffers是一個列表理解,就像在您發布的代碼中一樣,那么只要這個局部變量存在(即在 cffi_wrap() 的整個持續時間內),所有創建的 numpy數組還活着。 這允許您在下一行執行ffi.from_buffer(memoryview(...))並確保它們都是指向有效數據的指針。

如果將arr_param_buffers替換為生成器表達式,它會一一生成新的 numpy 數組,對它們調用ffi.from_buffer(memoryview(param)) ,然后將它們扔掉。 ffi.from_buffer(x)返回一個應該使x保持活動狀態的對象,但x == memoryview(nd)我所知,也許x == memoryview(nd)本身並不能使 numpy 數組nd保持活動狀態。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM