UTF-8: как быстрее измерить длину строки в PHP

Я потихоньку буду писать как получается оптимизировать самые важные функции работы с UTF-8 в PHP. Оформлять буду как продолжение своей эпопеи перевода наше внутренней «Вики» на UTF-8 (в ближайшее время добавлю оглавление).

Сейчас, после перевода «Вики» мы столкнулись с тем, что некоторые операции занимают непозволительно много времени. Кое-какие проблемы решаются моими итераторами для строки (прямым и обратным), но и другие оптимизации приходится делать.

Простые оптимизации я уже применил: выкинул из класса UTF-8 проверки на self::ON (по этой константе я определял включена ли в проекте поддержка UTF-8, сейчас в ней необходимости уже нет) и сделал другие микрооптимизации, теперь пора посмотреть на методы моего класса UTF.

Одна из самых частоиспользуемых функций — strlen, которая определяет длину строки. Я всегда считал, что самый быстрый способ подсчитать длину UTF-строки в PHP, это вызывать strlen(utf8_decode(…)).

Мои тесты показывают что это не так. Самый быстрый способ (по крайней мере в PHP 5.3.2) — это mb_strlen, strlen/utf8_decode — на втором месте, потом идёт sizeof+preg_split, а самый медленный — iconv_strlen.

Для интереса я вкомпилил в PHP функцию для быстрого подсчёта длины строки в UTF-8, найденную в интернете, выигрыш по сравнению с mb_strlen незначителен:

bolk-dev ~/uni/ $ php ../test/test_strlen.php | sort -k2 -t:
Fast UTF-8: 0.68232107162476
mb_strlen: 0.88710689544678
strlen/utf8_decode: 1.5211808681488

Это тысяча итераций на файле в 400КБ.

Я оставил функцию mb_strlen.

Добавлено позднее: другая быстрая функция дала ещё худший результат: 0,79, против прежнего варианта в 0,68.

Добавлено ещё позже: а вот третья функция показала действительно впечатляющие результаты:

bolk-dev ~/uni/ $ php ../test/test_strlen.php | sort -k2 -t:
More Fast UTF-8:  0.12948799133301
mb_strlen: 0.88710689544678
strlen/utf8_decode: 1.5211808681488

Это уже дело — она почти в 7 раз быстрее лучшего результата PHP.

Вкратце, алгоритм такой: строка циклом выравнивается по границе четырёх (на 64-битных системах — 8) байт, далее читается сразу по четыре (или восемь) байт и внутри каждого кусочка одним выражением считается сколько там байт, с которых начинается символ. Поэтому на моей 64-битной системе семикратный выигрыш (на 32 битах будет примерно в три раза).

Добавлено через несколько дней: есть и ещё более быстрая функция.

16 комментариев

Новый год в Казани

Новый год мы проводим в Казани. Вылетаем из Москвы 31-го, прилетаем назад 10-го.

2 комментария

Судьба PHP6

Поговорил с одним из разработчиков PHP по поводу судьбы PHP6, самое ожидаемое изменение которого — переход на юникодные строки. Так вот Антон Довгаль рассказал, что проект, по сути, заброшен. Те несколько человек, которые занимались проектом, либо уволились, либо потеряли к нему интерес и сейчас считается, что поддержка юникодных строк в языке не так уж и нужна.

На примере своего опыта разработки и перевода проектов на PHP на UTF-8, скажу это не так. В Пайтоне, где таких проблем нет, работать гораздо проще и приятнее.

То, что в PHP приходится для поддержки Юникода работать с UTF-8, а не с UTF-32 сильно снижает производительность всех строковых операций. И добро бы, если бы для всех функций были юникодные аналоги, так это ведь не так.

Работать в PHP с UTF-32 нельзя, если вы собираетесь использовать регулярные выражения: библиотека PCRE, предназначенная для работы с регулярными выражениями, понимает только две кодировки: latin-1 (по всей видимости) и UTF-8. Кроме того, функции, использующие локаль или ICU так же работают только с UTF-8.

Если бы этот язык нативно поддерживал UTF-32… Мечты-мечты.

15 комментариев

Ближе к народу

Ближе к народу (45.87КиБ)

Сфотографировал в казанском супермаркете «Перекрёсток».

2 комментария

Карта тела от «Гугла»

Bodymap (25.09КиБ)

Сегодня уже все написали о сервисе «Google body browser». Работает только в браузерах, поддерживающих WebGL (на данный момент — FireFox 4.0b7 и свежие версии «Хрома»).

Я наверное час утром изучал внутреннее устройство человека (там можно включить названия органов и регулировать «прозрачность»). Вот вы знаете где у вас в точности находится желудок, поджелудочная, селезёнка?

6 комментариев