Решение Кевина безопасно и должно быть по умолчанию в более крупном проекте, где вы просто не знаете, как будет использоваться ваша функция - поэтому полезно знать, что базовый буфер заблокирован и нет элементовможет быть добавлен в него из другого потока - это означает, что указатель, который мы передаем подпрограмме C, не будет признан недействительным.
Если бы функция имела подпись с типизированным представлением памяти, она бы даже быламожно использовать его для array.array
и других буферов, таких как numpy-массивы, например:
def Indexer(int[:] a):
Этот ответ пытается ответить на вопрос, каковы издержки просмотра типизированной памяти по сравнению с небезопасным решением сarray.array
.Для этого мы рассмотрим следующий пример, он проще, но временные характеристики похожи на исходную функцию:
%%cython
cimport cython
import array
from cpython cimport array
def with_array(array.array a):
cdef int *pa = a.data.as_ints #I used wrong syntax in my comments sorry for that!
return pa[0]
def direct_memview(int[::1] a):
return a[0]
def create_memview(a):
cdef int[:] pa=a
return a[0]
А теперь:
>>> import array
>>> a=array.array('i',range(1000))
>>> %timeit with_array(a)
160 ns ± 8.62 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
>>> %timeit direct_memview(a)
706 ns ± 22.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
>>> %timeit create_memview(a)
732 ns ± 19.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Так что в основном безопасная функцияЧем в 4 раза медленнее, тем меньше становится, тем больше работы выполняется в функции.
Еще одно интересное наблюдение: документация относится к direct_memory
как без издержек и к create_memview
как overhead
, но разница не так уж велика (даже неясно,существует!) по сравнению с небезопасным использованием.
Разница будет еще больше, если мы передадим numpy-массивам функции:
>>> import numpy as np
>>> b=np.array(a, dtype=np.int32)
>>> %timeit direct_memview(b)
1.48 µs ± 64.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
>>> %timeit create_memview(b)
1.54 µs ± 28.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Служебные значения numpy-массивов в два раза больше, чем array.array
, так что array.array
кажется лучшим выбором для облегченной задачи.
Мой вывод от этого: возможно, стоит использовать небезопасную версию, но я бы сделал это, только если уверенчто представление типизированной памяти действительно является узким местом и существует только один поток.