Я понимаю, что и Java, и Perl изо всех сил пытаются найти универсальный размер буфера, подходящий для всех размеров, при чтении в файлах, но я считаю, что их выбор все более устарел, и у меня возникают проблемы при изменении выбора по умолчанию, когда это касается Perl.
В случае с Perl, который, по моему мнению, использует буферы 8K по умолчанию, аналогично выбору Java, я не могу найти ссылку с помощью поисковой системы perldoc (на самом деле Google) на то, как увеличить размер буфера ввода файла по умолчанию, скажем, 64K.
Из приведенной выше ссылки, чтобы показать, как 8K буферы не масштабируются:
Если в каждой строке обычно содержится около 60 символов, то в файле из 10000 строк содержится около 610 000 символов. Строковое чтение файла с буферизацией требует только 75 системных вызовов и 75 ожиданий диска вместо 10 001.
Таким образом, для файла из 50 000 000 строк, содержащего 60 символов в строке (включая символ новой строки в конце), с буфером 8 КБ, будет выполнено 366211 системных вызовов для чтения файла 2,8 ГБ. Кроме того, вы можете подтвердить это поведение, посмотрев на дельту чтения диска при вводе-выводе (по крайней мере, в Windows, top в * nix тоже показывает то же самое, я уверен) в списке процессов диспетчера задач, как и ваша Perl-программа чтение текстового файла занимает 10 минут:)
Кто-то задал вопрос об увеличении размера входного буфера Perl для perlmonks, кто-то ответил здесь , что вы можете увеличить размер "$ /" и, таким образом, увеличить размер буфера, однако из perldoc:
Установка $ / для ссылки на целое число, скаляр, содержащий целое число, или скаляр, который может быть преобразован в целое число, будет пытаться читать записи вместо строк, при этом максимальный размер записи является ссылочным целым числом.
Поэтому я предполагаю, что это на самом деле не увеличивает размер буфера, который Perl использует для чтения вперед с диска при использовании типичного:
while(<>) {
#do something with $_ here
...
}
идиома "строка за строкой".
Теперь может случиться так, что другая версия «прочитайте запись за раз, а затем проанализируйте ее в строки» в общем случае будет быстрее, чем приведенная выше версия кода, и обойдёт основную проблему со стандартной идиомой и не сможет изменить размер буфера по умолчанию (если это действительно невозможно), потому что вы можете установить «размер записи» на что угодно, а затем разбирать каждую запись на отдельные строки, и надеяться , что Perl поступит правильно и завершится выполнение одного системного вызова на запись, но это добавляет сложности, и все, что я действительно хочу сделать, - это получить легкий выигрыш в производительности, увеличив буфер, используемый в приведенном выше примере, до достаточно большого размера, скажем, 64 КБ, или даже настроив этот размер буфера на оптимальный размер для длинных операций чтения с использованием тестового сценария в моей системе без дополнительных хлопот.
В Java все намного лучше, если идет прямая поддержка увеличения размера буфера.
В Java я считаю, что текущий размер буфера по умолчанию, который использует java.io.BufferedReader, также составляет 8192 байта, хотя современные ссылки в документах JDK двусмысленны, например, 1,5 документа говорят только:
Размер буфера может быть указан или размер по умолчанию может быть принят. Значение по умолчанию достаточно велико для большинства целей.
К счастью, с Java вам не нужно доверять разработчикам JDK, которые приняли правильное решение для вашего приложения, и можете установить свой собственный размер буфера (64K в этом примере):
import java.io.BufferedReader;
[...]
reader = new BufferedReader(new InputStreamReader(fileInputStream, "UTF-8"), 65536);
[...]
while (true) {
String line = reader.readLine();
if (line == null) {
break;
}
/* do something with the line here */
foo(line);
}
Существует только так много производительности, которую вы можете выжать из анализа одной строки за раз, даже с огромным буфером и современным оборудованием, и я уверен, что есть способы получить каждую унцию производительности от чтения в файле читая большие многострочные записи и разбивая каждый из них на токены, а затем выполняя работу с этими токенами один раз для каждой записи, но они добавляют сложности и крайние случаи (хотя, если в чистом Java есть элегантное решение (только с использованием функций, представленных в JDK 1.5), что было бы круто об этом знать). Увеличение размера буфера в Perl решило бы, по крайней мере, 80% проблем с производительностью для Perl, оставив все как есть.
Мой вопрос:
Есть ли способ отрегулировать этот размер буфера в Perl для описанной выше типичной идиомы "строка за строкой", аналогично тому, как размер буфера был увеличен в примере с Java?