Встроенная функция Cython с массивом numpy в качестве параметра

Хеш-таблица синхронизируется, тогда как HashMap не. Это делает Хеш-таблицу медленнее, чем Hashmap.

Для нерезьбовых приложений, используйте HashMap, так как они - иначе то же с точки зрения функциональности.

17
задан Ali 5 July 2014 в 22:24
поделиться

1 ответ

1122 Прошло более 3 лет с тех пор, как вопрос был опубликован, и за это время был достигнут значительный прогресс. В этом коде (Обновление 2 вопроса):

# cython: infer_types=True
# cython: boundscheck=False
# cython: wraparound=False
import numpy as np
cimport numpy as np

cdef inline inc(np.ndarray[np.int32_t, ndim=2] arr, int i, int j):
    arr[i, j]+= 1

def test1(np.ndarray[np.int32_t, ndim=2] arr):
    cdef int i,j    
    for i in xrange(arr.shape[0]):
        for j in xrange(arr.shape[1]):
            inc(arr, i, j)

def test2(np.ndarray[np.int32_t, ndim=2] arr):    
    cdef int i,j    
    for i in xrange(arr.shape[0]):
        for j in xrange(arr.shape[1]):
            arr[i,j] += 1

Я получаю следующее время:

arr = np.zeros((1000,1000), dtype=np.int32)
%timeit test1(arr)
%timeit test2(arr)
   1 loops, best of 3: 354 ms per loop
1000 loops, best of 3: 1.02 ms per loop

Таким образом, проблема воспроизводима даже после более чем 3 лет. Cython теперь имеет типизированных просмотров памяти , AFAIK он был введен в Cython 0.16, поэтому недоступен на момент публикации вопроса. С этим:

# cython: infer_types=True
# cython: boundscheck=False
# cython: wraparound=False
import numpy as np
cimport numpy as np

cdef inline inc(int[:, ::1] tmv, int i, int j):
    tmv[i, j]+= 1

def test3(np.ndarray[np.int32_t, ndim=2] arr):
    cdef int i,j
    cdef int[:, ::1] tmv = arr
    for i in xrange(tmv.shape[0]):
        for j in xrange(tmv.shape[1]):
            inc(tmv, i, j)

def test4(np.ndarray[np.int32_t, ndim=2] arr):    
    cdef int i,j
    cdef int[:, ::1] tmv = arr
    for i in xrange(tmv.shape[0]):
        for j in xrange(tmv.shape[1]):
            tmv[i,j] += 1

С этим я получаю:

arr = np.zeros((1000,1000), dtype=np.int32)
%timeit test3(arr)
%timeit test4(arr)
1000 loops, best of 3: 977 µs per loop
1000 loops, best of 3: 838 µs per loop

Мы находимся почти там и уже быстрее, чем старомодный способ! Теперь функция inc() может быть объявлена ​​ nogil , поэтому давайте объявим это так! Но упс:

Error compiling Cython file:
[...]

cdef inline inc(int[:, ::1] tmv, int i, int j) nogil:
    ^
[...]
Function with Python return type cannot be declared nogil

А-а-а, я полностью пропустил, что отсутствует тип возврата void! Еще раз, но теперь с void:

cdef inline void inc(int[:, ::1] tmv, int i, int j) nogil:
    tmv[i, j]+= 1

И, наконец, я получаю:

%timeit test3(arr)
%timeit test4(arr)
1000 loops, best of 3: 843 µs per loop
1000 loops, best of 3: 853 µs per loop

Так же быстро, как ручная установка!


Теперь просто для забавы я попробовал Numba по этому коду:

import numpy as np
from numba import autojit, jit

@autojit
def inc(arr, i, j):
    arr[i, j] += 1

@autojit
def test5(arr):
    for i in xrange(arr.shape[0]):
        for j in xrange(arr.shape[1]):
            inc(arr, i, j)

Я получил:

arr = np.zeros((1000,1000), dtype=np.int32)
%timeit test5(arr)
100 loops, best of 3: 4.03 ms per loop

Даже если он в 4,7 раза медленнее, чем Cython, скорее всего потому, что JIT-компилятору не удалось встроить inc(), я думаю, что это УДИВИТЕЛЬНО! Все, что мне нужно было сделать, это добавить @autojit и не нужно было путать код с неуклюжими объявлениями типов; 88-кратное ускорение практически за ничто!

Я пробовал другие вещи с Numba, такие как

@jit('void(i4[:],i4,i4)')
def inc(arr, i, j):
    arr[i, j] += 1

или nopython=True, но не смог улучшить его дальше.

Улучшение встраивания находится в списке разработчиков Numba , нам нужно только подать больше запросов, чтобы у него был более высокий приоритет. ;)

18
ответ дан 30 November 2019 в 12:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: