Pull to refresh

Comments 33

Интересно. Что за профайлер? Подедитесь?

$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.

Интересная задачка. Но однажды я столкнулся с ещё более интересной - люди скинули JSON-лог весом более гигабайта. И тут уже совсем другой уровень сложности: структура JSON-а и уровни вложенности заранее неизвестны вообще, и весь этот файл - это по сути одна строка. То есть, у тебя есть всего одна строка весом более гигабайта и на имеющейся мощности её нельзя просто взять и json_decode-нуть, т.к. для этого не хватает памяти. И вот тут начинается самое интересное...)) Когда у тебя много однородных строк с понятной структурой а-ля CSV - это сильно проще)

Задачка действительно интересная, но streaming json parsers php вполне гуглятся.

убрав аргумент len из вызова fgets()

Либо изменить на 8192, дефолтное значение.

А если вместо fgets взять stream_get_line то можно ускориться ещё процентов на 50.

https://gist.github.com/joseluisq/6ee3876dc64561ffa14b

Вы меня извините, но чей-то непонятный гист и заминусованный комментарий из мануала - это так себе источники. Вот если бы были ссылки, например, на исходный код, с конкретным указанием на причину "медленности" 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

Sign up to leave a comment.