Ускорение Cython.Списки против Numpy Arrays - PullRequest
2 голосов
/ 09 июля 2019

В настоящее время я пытаюсь ускорить процедуру Cython, которая сильно зависит от списков. В основном, я хотел бы увеличить скорость индексации в этих списках.

Согласно документации, рекомендуется использовать массивы Numpy с представлениями памяти.

https://cython.readthedocs.io/en/latest/src/userguide/memoryviews.html

Однако, когда я изменяю свои списки на пустые массивы (большинство из них просто целые числа), код становится намного медленнее. Я хотел бы лучше понять, почему это происходит, поскольку я ожидаю, что массивы будут намного быстрее, чем списки.

Я не могу показать точный код, над которым я работаю, но я буду использовать пример, чтобы передать мою проблему.

Итак, допустим, у меня есть эти три функции, которые подсчитывают количество элементов в списке. Пример: если список:

test_list = [1, 2, 3, 4, 1, 1, 3, 4]

, тогда вывод будет [3, 1, 2, 2].

def counter(test_list):
""" The Counter was imported from collections naturally """
    output = [0] * len(set(test_list))
    for key, value in Counter(test_list).items():
        output[key - 1] = value
    return output

Теперь две функции Cython, которые вычисляют одно и то же:

def cython_counter_collections(test_list):

    cdef int key, value

    output = [0] * len(set(test_list))
    for key, value in Counter(test_list).items():
        output[key - 1] = value
    return output

и

def cython_counter_manual(test_list):

    cdef long[:] new_test_list = np.array(test_list)
    cdef int size, val, i, uniques_size
    size = new_test_list.shape[0]
    uniques_size = np.unique(new_test_list).shape[0]

    i = 0
    output = [0] * uniques_size
    while i < size:
        val = new_test_list[i]
        output[val-1] += 1
        i+=1

    return output

Для последней функции я использовал import и cimport numpy в качестве np.

Я бы предположил, что последняя функция, cython_counter_manual, будет поститься, поскольку я использую массив numpy и не использую вызовы Python. Я измеряю время, используя timeit, например, вот так

print(timeit("counter(test_list)", globals=globals(), number=n_its))

для всех функций и результаты:

Python Code
3.12014272399756 s

Cython Counter Collections
2.883361326999875 s

Cython Counter Manual
11.205707081000583 s

Почему это происходит? Как это стало намного медленнее? Спасибо!

...