Как читать целые числа из файла, когда производительность является проблемой?
Я выполняю некоторые задания на CodeEval. В основном задача очень проста: "Распечатайте сумму всех целых чисел, считанных из файла".
Мое решение следующее:
import java.io.File;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.FileReader;
public class SumIntegersFromFile {
public static void main(String args[]) throws IOException{
File file = new File(args[0]);
BufferedReader br = new BufferedReader( new FileReader(file));
String line;
int i=0;
while((line=br.readLine())!=null){
int k = Integer.parseInt(line);
i+=k;
}
br.close();
System.out.println(i);
}
}
Но мне сказали, что это решение не оптимально с точки зрения производительности.
Код основан на рекомендациях в вопросе Лучший способ прочитать текстовый файл. Единственное отличие здесь в том, что я читаю целые числа вместо строк.
Каков наиболее эффективный способ чтения целых чисел из файла на Java?
Ответы
Ответ 1
Если вам явно не указано иначе, вы не должны предполагать, что общее количество будет соответствовать int
. Попробуйте изменить тип i
на long
или даже BigInteger
и посмотреть, не влияет ли это на ваш счет.
Вы можете попробовать сделать то же самое с k
(и используя Long.parseLong(line)
). Это будет зависеть от точной формулировки вопроса, но, возможно, отдельные значения могут превышать пределы int
.
Еще одна вещь... вопрос, как вы его сформулировали, просто говорит, что вы должны суммировать все целые числа. Это оставляет открытой возможность того, что будут строки, которые не являются целыми числами, и в этом случае вы должны пропустить их, а не бросать NumberFormatException
(что и будет делать ваш код в данный момент).
(И, предположительно, вам сказали, что это одна запись в строке...)
Но если вы хотите выжать каждый последний бит производительности, вам нужно прочитать файл как двоичный, а не строковый: переключение каждой строки в String
просто слишком дорого. Подробный отчет о том, как это сделать, можно найти в этом вопросе о суммировании целых чисел из текстового файла.
Ответ 2
Я не вижу ничего плохого в производительности вашего кода. То есть, я оспариваю утверждение о том, что у вашей программы что-то не так.
Чтение данных из файлов или по сети происходит на несколько порядков медленнее, чем манипулирование данными в памяти. Таким образом, производительность кода, который смешивает операции ввода-вывода с некоторыми манипуляциями с данными в памяти, обычно занимает время, затраченное на ввод-вывод. Режимы манипулирования данными в памяти редко бывают полезны. Если операции ввода-вывода выполняются параллельно с манипулированием данными (что будет иметь место, если O/S выполняет некоторые операции с чтением), обработка данных может быть практически бесплатной: ускорение обработки данных не приведет к сокращению времени, уменьшение времени процессора для обработки данных будет точно компенсировано увеличением количества времени, в течение которого программа блокируется при ожидании ввода.
Программы, выполняющие операции ввода-вывода и требующие хорошей производительности, должны уменьшать количество времени, которое они тратят на блокирование, ожидающее ввода-вывода. Они должны работать таким образом, чтобы они могли использовать преимущества оптимизации, обеспечиваемой оборудованием и операционной системой, чтобы уменьшить количество блокировок.
Важно отметить, что на низком уровне диски и сети не работают с небольшим количеством байтов для каждой операции. Они используют более крупные единицы пакетов или блоков. Взаимодействие с операционной системой для чтения меньше байт, чем хранится в одном блоке диска, является расточительным. Программы избегают делать это путем буферизации ввода-вывода, поэтому сама программа меняет последовательность многих операций ввода-вывода на меньшие, но более крупные операции. Вы используете BufferedReader
, поэтому вы уже это делаете.
Операционная система, скорее всего, выполнит предварительную проверку: если вы спросите байты в блоке в начале файла, то предположите, что вы, вероятно, будете читать файл последовательно, поэтому было бы полезно для него чтобы также получить некоторые из последующих блоков файла, в ожидании вашей программы, также нуждающейся в них. Чтение файлов последовательно обеспечивает лучшую производительность. Вы уже это делаете.