Подтвердить что ты не робот

Идиоматический способ сделать список /dict в Cython?

Моя проблема: я обнаружил, что обработка больших наборов данных с необработанным С++ с использованием STL-карты и вектора часто может быть значительно быстрее (и с меньшим объемом памяти), чем с использованием Cython.

Я полагаю, что часть этого штрафа за скорость связана с использованием списков Python и dicts и что могут быть некоторые приемы использования менее обремененных структур данных в Cython. Например, эта страница (http://wiki.cython.org/tutorials/numpy) показывает, как быстро сделать массивы numpy в Cython, предопределив размер и типы массива ND.

Вопрос: Есть ли способ сделать что-то подобное со списками /dicts, например. указав примерно, сколько пар или пар (ключ, значение) вы ожидаете иметь в них? То есть, существует ли идиоматический способ преобразования списков /dicts в (быстрые) структуры данных в Cython?

Если нет, я думаю, мне просто нужно написать его на С++ и обернуть в импорт Cython.

4b9b3361

Ответ 1

Cython теперь имеет поддержку шаблонов и поставляется с объявлениями для некоторых контейнеров STL.

См. http://docs.cython.org/src/userguide/wrapping_CPlusPlus.html#standard-library

Вот пример, который они дают:

from libcpp.vector cimport vector

cdef vector[int] vect
cdef int i
for i in range(10):
    vect.push_back(i)
for i in range(10):
    print vect[i]

Ответ 2

Выполнение подобных операций в Python, как на С++, может быть медленнее. list и dict на самом деле реализованы очень хорошо, но вы набираете много накладных расходов, используя объекты Python, которые более абстрактны, чем объекты С++, и требуют гораздо большего поиска во время выполнения.

Кстати, std::vector реализуется довольно похоже на list. std::map, однако, фактически реализуется таким образом, что многие операции медленнее, чем dict по мере того, как его размер становится большим. Для подходящих больших примеров каждый dict преодолевает постоянный коэффициент, с которым он медленнее, чем std::map, и будет быстрее выполнять операции, такие как поиск, вставка и т.д.

Если вы хотите использовать std::map и std::vector, ничто не останавливает вас. Вам придется обернуть их самостоятельно, если вы хотите выставить их на Python. Не будьте шокированы, если эта упаковка потребляет все или большую часть времени, которое вы надеялись сохранить. Я не знаю о каких-либо инструментах, которые делают этот автоматический для вас.

Существуют вызовы API C для управления созданием объектов с некоторыми деталями. Вы можете сказать: "Составьте список, по крайней мере, с этими многими элементами", но это не улучшает общую сложность операции создания и заполнения списка. Это не изменится намного позже, когда вы пытаетесь изменить свой список.

Мой общий совет

  • Если вам нужен массив фиксированного размера (вы говорите о задании размера списка), вы можете действительно хотеть что-то вроде массива numpy.

  • Я сомневаюсь, что вы получите любое ускорение, которое вы хотите использовать std::vector over list для общей замены кода. Если вы хотите использовать его за кулисами, он может дать вам удовлетворительный размер и улучшение пространства (я, конечно, не знаю, не измеряя и не делаю.)).

  • dict действительно делает свою работу очень хорошо. Я определенно не стал бы вводить новый тип общего назначения для использования в Python на основе std::map, который имеет худшую алгоритмическую сложность во времени для многих важных операций и, по крайней мере, в некоторых реализациях, оставляет некоторые оптимизации пользователю, что dict уже есть.

    Если бы мне захотелось что-то, что немного походило на std::map, я бы, вероятно, использовал базу данных. Обычно это то, что я делаю, если вещи, которые я хочу хранить в dict (или, если на то пошло, вещи, хранящиеся в list), становятся слишком большими, чтобы я чувствовал себя комфортно в памяти. Python имеет sqlite3 в stdlib и драйверах для всех других основных доступных баз данных.

Ответ 3

С++ быстрый не только из-за статических деклараций вектора и элементов, которые входят в него, но в решающей степени, потому что с использованием шаблонов /generics указывается, что вектор будет содержать только элементы определенного типа, например. вектор с кортежами трех элементов. Cython не может сделать это последнее, и это звучит нетривиально - его нужно было бы внедрить во время компиляции, как-то (typechecking во время выполнения - это то, что уже делает Python). Так что прямо сейчас, когда вы выталкиваете что-то из списка в Cython, нет никакого способа заранее знать, какой тип он есть, и помещая его в типизированную переменную, добавляет только typecheck, а не скорость. Это означает, что в этом отношении нет возможности обойти интерпретатор Python, и мне кажется, что это самый важный недостаток Cython для выполнения не численных задач.

Ручным способом решения этого является подкласс python list/dict (или, возможно, std::vector) с классом cdef для определенного типа элемента или комбинации клавиш. Это будет означать то же, что и код, который генерируют шаблоны. Пока вы используете результирующий класс в коде Cython, он должен обеспечить улучшение.

Использование баз данных или массивов просто решает другую проблему, поскольку это касается размещения в контейнерах произвольных объектов (но с определенным типом, а предпочтительно класса cdef).

И std:: map не следует сравнивать с dict; std:: map поддерживает ключи в отсортированном порядке, потому что это сбалансированное дерево, dict решает другую проблему. Лучшим сравнением будет диктофон и хэш-таблица Google.

Ответ 4

Вы можете посмотреть стандартный array модуль для Python, если это подходит для вашей настройки Cython. Я не уверен, так как никогда не использовал Cython.

Ответ 5

Невозможно получить собственные списки Python/dicts со скоростью карты/вектора С++ или даже где-нибудь близко. Это не имеет ничего общего с объявлением распределения или типа, но скорее оплачивает накладные расходы переводчика. Пример, который вы упоминаете (numpy), является расширением C и написан именно на C по этой причине.