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

Обработка строк в Cython

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

(EDIT: Я делаю такие вещи, как поиск самой длинной общей подстроки, запуская множество регулярных выражений, которые могут быть лучше выражены как конечные машины в c, снятие комментариев с HTML и т.д.)

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

Юникод также может быть большой проблемой.

Мои вопросы:

  • Должен ли я даже беспокоиться о Cython для струнных вещей? Кто-нибудь имеет опыт работы с этим типом обработки на языке cython и может делиться?
  • Я что-то пропустил в документах Cython? Кто-нибудь знает учебник/ссылку/документацию о работе со строками в Cython?
4b9b3361

Ответ 1

Я проголосовал за ответ "profile it", но хотел бы добавить это: по возможности наилучшей оптимизации вы можете использовать стандартные библиотеки Python или встроенные функции для выполнения задач, которые вы хотите. Они обычно реализуются в C и обеспечивают производительность, в целом эквивалентную любому расширению, включая расширения, написанные в Cython. Если ваши алгоритмы выполняют символ по символьным циклам в Python, тогда это должны быть первые вещи, если это возможно.

Но если у вас есть алгоритмы, которые не могут быть переработаны с точки зрения встроенных или других существующих стандартных библиотек, Cython кажется разумным. Он просто компилирует псевдо-Python до собственного кода и, как и подходит для строковых операций, как и любая другая операция. Но я не уверен, что вы увидите большую пользу от использования Cython, если вы просто передадите его идиоматический код Python. Максимальное преимущество будет достигнуто, если вы сможете переписать некоторые или все из каждого алгоритма в C, чтобы операции на низком уровне не постоянно переводили переменные через барьер Python/C.

Наконец, Unicode - вы подразумевали, что это может быть "большой проблемой", но не указали, как вы его используете. Cython предположительно создаст C-код, который вызывает соответствующие API-интерфейсы Python, которые обрабатывают Unicode, поэтому функциональность вряд ли будет ограничена. Однако обработка строк Unicode в C нетривиальна и может означать, что идея переписать некоторые из ваших алгоритмов на C для повышения производительности не стоит усилий. Многие классические струнные алгоритмы просто не будут работать во многих кодировках Юникода, которые не являются "строками" в традиционном смысле наличия 1 единицы хранения на символ.

Ответ 2

"Смешно легко" - очень относительный термин. "Начало работы" - вот что. Написание надежных расширений в C требует очень пристального внимания к таким вещам, как подсчет ссылок, распределение/освобождение памяти и обработка ошибок. Cython многое делает для вас.

Строка, не относящаяся к юникоду в Cython, представляет собой либо объект Python str, либо массив из char, как и в C. Какая документация по Cython, по вашему мнению, вам нужна?

Я рекомендую вам попробовать Cython для себя. НО прежде чем вы это сделаете, я настоятельно рекомендую вам изучить ваш код на Python для неэффективности. Иногда вы можете легко получать большие ускорения.

Например, сжатие пробелов пробелов... с использованием

re.sub(' +', ' ', s) # one space in pattern

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

re.sub('  +', ' ', s) # two spaces in pattern

производит точно такие же результаты и может работать быстрее... пусть видит:

Все пробеги длится 1: он работает в 3,4 раза быстрее. Не показано: чем длиннее входная строка, тем лучше.

\python26\python -mtimeit -s"s='now is the winter of our discontent'; import re; x = re.compile(' +').sub" "x(' ', s)"
100000 loops, best of 3: 8.26 usec per loop

\python26\python -mtimeit -s"s='now is the winter of our discontent'; import re; x = re.compile('  +').sub" "x(' ', s)"
100000 loops, best of 3: 2.41 usec per loop

При одном прогоне, имеющем длину 2, коэффициент скорости равен 2,5. При всех прогонах, имеющих длину 2, коэффициент скорости равен 1,2. Все рассмотрено, не плохой доход от инвестиций в 1 нажатие клавиши.

Ответ 3

Просто для полноты, что я закончил делать, просто написать (некоторые из) код манипуляции строкой в ​​C.

Как оказалось, смешно легко, чтобы начать писать c расширения для python. Строки Unicode - это просто массивы Py_UNICODE, которые являются int или короткими, в зависимости от сборки python.

Я получил код преобразования для улучшения x20, например

s = re.sub(r' +', ' ', s)

- c. У меня были аналогичные улучшения с более сложными регулярными выражениями, но код c очень быстро сходит с ума.

В целом моя пропускная способность увеличилась на 20% после перезаписи. Я теперь ищу больше вещей, чтобы переписать...

Ответ 4

Это очень интересная проблема. Cython в своем ядре является инструментом для интеграции python с типами данных C. Он не предоставляет каких-либо функциональных возможностей для работы со строками, вероятно, потому, что для этого не так много спроса, как для конкретных функций Numpy.

Сказав это, вы вполне можете использовать Cython для взаимодействия с существующими библиотеками C/С++, предназначенными для обработки типов проблем, которые вы описываете. Для обработки HTML/XML вы можете, например, посмотреть libxml. Однако есть (конечно) готовые привязки python, уже доступные для этого. Я широко использовал lxml для обработки HTML, и он делает все, что мне нужно, и делает это быстро, плюс он отлично справляется с юникодом.

В вашем случае я бы предположил, что комбинация lxml и пользовательских C-функций будет лучше всего. Например, вы можете "легко" выполнить быструю функцию поиска самых длинных подстрок в C, поскольку это можно было бы сделать на уровне байтов (напомните, что строка на C является всего лишь char *, которая представляет собой массив байтов). Затем вы можете отобразить их обратно на python (который Cython сделает для вас очень легким) и продолжить в unicode абстрагированном небе:). Конечно, не тривиально, но может стоить усилий, если ваша производительность приложения зависит от него.

Тогда есть, конечно, хорошие (хотя и нетривиальные) подходы к работе с unicode в C/С++. Эта статья Эвана Джонса может помочь вам решить, стоит ли это делать.

Ответ 5

Недавно я познакомился с Cython и имел большой успех, обертывая большие библиотеки C и С++ для использования в значительных проектах. Некоторые из сгенерированных расширений Python фактически уже работают в нашей производственной среде. Итак, во-первых, Cython, imo, определенно хороший выбор.

При этом вам следует подумать о том, действительно ли вы хотите написать весь свой код в Cython или хотите написать код C/С++ и просто сделать эти функции доступными из Cython. Очевидно, это частично зависит от вашего уровня комфорта с C и/или С++.

Как вы работаете со строками, вы могли бы сделать жизнь проще, используя std::string из С++, а не char*. Его можно легко импортировать на cython с помощью from libcpp.string cimport string, тогда переменные могут быть объявлены с помощью типа строки с помощью стандартного cython cdef string ...

Ответ 6

Обратите внимание, что Cython фактически поддерживает тип Pyython Py_UNICODE, поэтому, например, вы можете напрямую перебирать строки Unicode или сравнивать символы на скорости C. См

http://docs.cython.org/src/tutorial/strings.html