Неэффективный ввод и вывод
Мое частое замечание к коду — неэффективный ввод-вывод. Примеры:
-
чтобы пройтись по строкам файла, человек читает его в память целиком и разбивает символами
\r\n
. Рано или поздно прилетает CSV на 5 гигабайт, и машине становится плохо. -
То же самое с джейсоном: есть стрим, но разработчик читает его в гигантскую строку, а потом парсит ее.
-
Нужно записать в файл 100 тысяч строк? Человек джойнит их разделителем, получает километровую строку и пишет в файл.
-
Различные кодирования — base64, gzip и другие — делаются также: данные читаются в память целиком, из них получается результат тоже в памяти.
-
При загрузке файла в S3 он целиком читается в байтовый массив, затем массив передается в запрос.
При этом разработчик обмазывает код вызовами gc в надежде, что это поможет.
Сколько подобных ошибок я исправил — не перечесть. В числе прочего был сервис, который падал от недостатка памяти, хотя ее было выделено запредельное количество. Оказалось, разработчик делал все из списка выше. Он получал огромные файлы, читал их в память, парсил, кодировал в JSON и gzip, используя строки и массивы. Когда код падал от OOM, он поднимал лимиты в облаке.
Это лишний раз подтверждает: сколько памяти ни дай, плохой код сожрет ее всю.
А решение простое — байтовые и символьные потоки. Ту же Джаву можно ругать за
многое, но в ней очень хорошие потоки (абстрактные классы Input-
и
OutputStream
, Reader
и Writer
). У них много наследников, каждый из которых
делает свою работу. Например, буферизирующий поток, который сглаживает
неравномерность сети и файлов. Потоки для сжатия, когда пишешь в него, а данные
сжимаются в полете. Потоки, связанные с файлами, сокетами или
устройствами. Потоки с подсчетом текущей строки и символа, потоки-пайпы (piped)
для “переливания” данных между тредами — всего этого навалом.
Легко найти сторонние потоки для подсчета MD5 и других хешей. Например, пишешь в
условный MD5OutputStream
, и хеш считается в полете. В конце вызываешь
.getHash, и готово.
Часто задача решается тем, что нужно построить стек потоков и скормить ему данные. Это труднее, чем прочитать файл в память и разбить на строки. Но не придется чинить в пятницу вечером.
Уделите время потокам ввода-вывода. Это прям очень полезная вещь.
Нашли ошибку? Выделите мышкой и нажмите Ctrl/⌘+Enter