Самый быстрый способ сохранить большие данные в файл - PullRequest
4 голосов
/ 05 ноября 2010

Я делаю некоторые числовые вычисления в Java, C # и C ++.Некоторые из них сохраняют много данных (в текстовый файл).Какой самый быстрый способ сделать это?

C ++ .

ofstream file;
file.open(plik);
for(int i=0;i<251;i++){
    for(int j=0;j<81;j++)
        file<<(i-100)*0.01<<" "<<(j-40)*0.01<<" "<<U[i][j]<<endl;
    file<<endl;
}

Что я предполагаю, очень быстро (я прав? :))

Java

void SaveOutput(double[][] U, String fileName) throws IOException
{
    PrintWriter tx = new PrintWriter(new FileWriter(fileName));
    for(int i=0;i<251;i++)
    {
        for(int j=0;j<81;j++)
        {
            tx.println(String.format("%e %e %e ",(i - 100) * dz, (j - 40) * dz, U[i][j]));
        }
        tx.println();
    }
    tx.close();
}

Пример C # похож.

и вот что меня беспокоит.Я делаю объект String для каждой строки (много мусора).В этом примере это не так много, но иногда у меня есть 10 000 000 строк.Это приводит меня к вопросам:

  1. Может ли пример c ++ быть быстрее?
  2. Должен ли я использовать StringBuilder для Java или, может быть, он также плох из-за количества строк
  3. Есть какой-нибудь другой способ или библиотека?
  4. А как насчет C #?

Спасибо

Ответы [ 8 ]

5 голосов
/ 05 ноября 2010

Профиль.Запустите код, рассчитайте время, посмотрите, сколько времени это займет.Если количество времени, которое это занимает, является приемлемым, используйте это.Если нет, выясните, какая часть занимает много времени для запуска, и оптимизируйте ее.

  • Сделайте это правильно.
  • Сделайте это быстро.

Этот порядок.(Некоторые люди добавляют «заставь его запускать / строить» перед этими двумя ...)

Тем не менее, я действительно запускал метрики для такого рода вещей раньше.Суть в том, что вы ждете диск, а диск безбожно медленный.Неважно, пишете ли вы на C, C ++ или Java, все они ждут жесткого диска.

Вот предыдущий пост , который я делал на разных/ O методы в C. Не совсем то, что вы ищете, но может быть информативным.

4 голосов
/ 05 ноября 2010

Одно слово: профиль.

Обратите внимание, что вставка std::endl в буферизованный (файловый) поток приводит к его сбросу, что, вероятно, ухудшит производительность (из языка POV это означает, что буфер выписан ", хотя это не обязательно означает, что доступ к физическому диску). Для простой печати новой строки используйте '\n' - это никогда не хуже.

2 голосов
/ 05 ноября 2010

Прежде всего: используйте буферизованный писатель!

Это может включать включение буферизации на канале в некоторых языках или использование BufferedWriter (в Java) или эквивалентного в других. Невыполнение этого требования может привести к гораздо худшей производительности , поскольку выходной поток может быть «переполнен» - приведенный выше пример кода нарушает это (FileWriter ничего не знает о буферизации)!

Во многих случаях доступ к ЦП и основной памяти можно считать «дешевым», а IO - «дорогим» - в таких тривиальных случаях, таких как этот, улучшение доступа к самому IO (например, буферизация, а не [перегрузка]) приведет в самых ощутимых выгод. Современные виртуальные машины и JIT делают то, что делают, и недолговечное размещение / перераспределение объектов, вероятно, является наименьшим из «беспокойств» здесь.

1 голос
/ 05 ноября 2010

Во-первых, обратите внимание, что эта связанная с вводом / выводом программа получит незначительное улучшение в зависимости от мелких деталей (например, если вы используете потоки C ++ или printf).

Для части C / C ++Некоторые говорят, что использование старых операций printf быстрее.Это может быть быстрее, но не на порядок, так что я бы не стал беспокоиться.

Что касается версии Java, я думаю, что она уже достаточно оптимизирована.

Не могу сказать, для C #, мой доктор не позволяет мне:)

1 голос
/ 05 ноября 2010

Используйте класс Java.nio для создания каналов. Каналы являются новыми для Java и намного быстрее, чем старые потоки. Вы также должны буферизировать запись. Я не могу вспомнить, если каналы буфера по умолчанию. Мне нужно прочитать кое-что, чтобы сказать тебе это.

Наконец, все в порядке, вы создаете много строк. Вы выбрасываете их немедленно. Я сомневаюсь, что это замедлит вашу запись на диск. Дисковый ввод-вывод намного медленнее, чем ЦП.

Вот то, о чем я думал:

fileChannel = new FileOutputStream("test.txt").getChannel();
for(int i=0;i<251;i++) {
  for(int j=0;j<81;j++) {
    fileChannel.write(ByteBuffer.wrap((String.format("%e %e %e ",(i - 100) * dz, (j - 40) * dz, U[i][j]) + "\n").toBytes());
  }
fileChannel.close();
0 голосов
/ 05 ноября 2010

Что касается Java, вам не нужно создавать все эти строки.Избавьтесь от String.format и напишите байты напрямую.

Используйте nio и профиль беспощадно

0 голосов
/ 05 ноября 2010

Лукас,

Во-первых, я знаю в основном C #, поэтому все здесь относится к .NET.

С количеством строк, с которыми вы имеете дело, я бы не стал создавать строкииспользовать StringBuilder.StringBuilder помогает создавать строки только из нескольких небольших сегментов.

Я думаю, что вам лучше всего использовать потоковые версии объектов файловой системы.Таким образом, вы вообще не храните строки, и поэтому использование вашей памяти должно быть довольно небольшим.

Кроме того, если у вас действительно мало памяти, вы всегда можете создать неуправляемую строку и P / Invoke вЭто.

Эрик

0 голосов
/ 05 ноября 2010

Я ожидаю, что будет быстрее использовать fprintf в C или C ++.

...