Comments 33
Интересно. Что за профайлер? Подедитесь?
Конечно(:
Используется профайлер для PHP от Datadog. Скриншоты, представленные в статье взяты из бэка Datadog.
$chunk_size = (int) ($size / $cpu_count);
Может так получится что размер чанка приведёт курсор чтения данных в середину строки и данные будут неверны.
Также стоит заметить что массивы в php это не самый быстрый способ хранения данных. Лучше использовать динамические структуры данных, например связанный список и реализовать его используя классы - ещё пару спичек можно будет сэкономить.
А вы сами пробовали такой вариант?
Код внимательнее посмотрите. Там граница сдвигается до новой строки после $chunk_size.
И где тут использовать списки? Нам для обработки каждой строки нужно искать станцию по id, что быстрее делать через хэш-таблицу (что встроено в массивы php).
Посмотрел внимательно код: если fseek переместит на начало строки, то строка не будет обработана. Если курсор будет перемещен на середину строки, строка не будет обработана. Просто пустое чтение строки вникуда. - я об этом и написал с начала.
В коде формируются массивы, а потом пробегает по массиву и выводим текст. Также можно поступить и мо списком построенным на классах, только список будет занимать меньше памяти чем массив множество копий массива внутри каждой функции.
Этот результат значительно отличается от того, что вы могли видеть в таблице лидеров исходной задачи, что объясняется использованием совсем другого аппаратного оборудования.
в очень малой степени. скачайте себе реализацию java и проверьте
Возможно стоило бы еще использовать DS\Map - это тоже может дать буст производительности. Особенно если сначала выделить всю нужную память.
Интересная статья. Как правило type hint в функциях и возвращаемых значениях, а также свойствах класса решает большинство вопросов по однозначному интерпретированию типа значения, в реальной практике. Пример показанный вами всегда рассматривал как Конвертацию, преобразование типа, в большинстве случаев и примеров он так и используется, даже в первоисточнике:
<?php
$foo = 10; // $foo — это целое число
$bar = (bool) $foo; // $bar — это логическое значение
?>
Не думал, что подобное использование может ускорить работу. Ведь конвертация это тоже операция.
Это ведь не как в C определение переменной.
int a = 0; // Добавление значения сразу
float c; // Создание переменной без значения
short b, y = 342; // Создание нескольких переменных
Сразу ясно, что она типизированной задается. А в примерах по php вообще не очевидно, что это преобразование приведет к ускорению.
// $temp = (float)substr($data, $pos2+1, -1);
$temp = substr($data, $pos2+1, -1) * 10; // а если попробовать целые числа
На мой взгляд самое интересное осталось за скобками. То, что сделал оптимизатор, можно было реализовать самому на PHP с -O0? Другими словами: возможно ли на PHP написать оптимальную программу?
Поместите исходный файл в память. Диск влияет на скорость, исключите это место. Выиграете ещё несколько секунд.
Ждём сравнительного теста на Go.
На той же яве уже всех победили за 2 секунды. https://www.infoq.com/news/2024/01/1brc-fast-java-processing/
Интересная задачка. Но однажды я столкнулся с ещё более интересной - люди скинули JSON-лог весом более гигабайта. И тут уже совсем другой уровень сложности: структура JSON-а и уровни вложенности заранее неизвестны вообще, и весь этот файл - это по сути одна строка. То есть, у тебя есть всего одна строка весом более гигабайта и на имеющейся мощности её нельзя просто взять и json_decode-нуть, т.к. для этого не хватает памяти. И вот тут начинается самое интересное...)) Когда у тебя много однородных строк с понятной структурой а-ля CSV - это сильно проще)
Задачка действительно интересная, но streaming json parsers php вполне гуглятся.
о, попадалась такая задача, была успешно решена с помощью вот такой штуки https://github.com/halaxa/json-machine
убрав аргумент len из вызова fgets()
Либо изменить на 8192, дефолтное значение.
А если вместо fgets взять stream_get_line то можно ускориться ещё процентов на 50.
Вы меня извините, но чей-то непонятный гист и заминусованный комментарий из мануала - это так себе источники. Вот если бы были ссылки, например, на исходный код, с конкретным указанием на причину "медленности" fgets - тогда можно было бы что-то советовать. А сейчас это просто новость от агентства ОБС.
Вы сами-то пробовали заменить это шило на мыло?
Практика - критерий истины. У меня для файла на 4 млн строк скорость получается 0.92 сек. против 0.75 сек.
Не 50 процентов, конечно, но 20 есть.
Показывайте код. Потому что например в коде ниже заслуга совсем не в замене шила на мыло.
$fp = fopen("_json.json", 'r');
$i = -1;
//while (($buffer = stream_get_line($fp, 65535, "\n")) !== false) {
while (($buffer = fgets($fp, 65535)) !== false) {
}
И при чем здесь Processing One Billion Rows Challenge, где читаются строки по 20 байт?
Понятия не имею. Автор читает 8192 байта через fgets. Я предложил читать через stream_get_line, который работает быстрее.
stream_get_line не работает быстрее. Возможно, в каком-то отдельном случае, на определенном наборе данных, эта функция оказалась быстрее (если вы не налажали с измерениями, как налажали с цифрами, быстро спрыгнув с 50 на 20%). Но ни в общем случае, ни в конкретном примере, который рассматривается в статье, сама по себе замена fgets на stream_get_line даст скорее замедление. А вот замена fgets + strpos на 2 stream_get_line - как раз даёт ускорение.
В большинстве случае, где надо читать данные из файла построчно, функция работает быстрее.
С цифрами никто не лажал, 50 процентов это результат из гиста. Вы бы следили за дискуссией.
Можно еще вместо fgets() использовать stream_get_line(). По моим тестам даёт еще примерно 25% производительности на однопотоке
while (!feof($fp)) {
$city = stream_get_line($fp, 0, ';');
$temp = (float)stream_get_line($fp, 0, "\n");
Интересно, что сама по себе замена fgets() на stream_get_line() ничего не даёт, кроме замедления. А вот замена ручного парсинга строки на получение нужных значений прямо из потока, как в вашем примере - действительно, даёт такой прирост.
Кстати, если выкинуть feof, то получается скостить еще процентов 10
Как я обработал один миллиард строк в PHP