Как данные, записанные в файл действительно, будут сбрасываться/синхронизироваться с блочным устройством с помощью Java.
Я пробовал этот код с помощью NIO:
FileOutputStream s = new FileOutputStream(filename)
Channel c = s.getChannel()
while(xyz)
c.write(buffer)
c.force(true)
s.getFD().sync()
c.close()
Я предположил, что c.force(true) togehter с s.getFD(). sync() должно быть достаточным, потому что doc для force состояния
Заставляет любые обновления этого файла канала записываться на запоминающее устройство, которое его содержит. Если этот файл канала находится на локальном запоминающем устройстве, то при возврате этого метода гарантируется, что все изменения, внесенные в файл с момента создания этого канала или с момента последнего вызова этого метода, будут записаны на это устройство. Это полезно для обеспечения того, чтобы критическая информация не терялась в случае сбоя системы.
В документации к sync указано:
Заставить все системные буферы синхронизировать с базовым устройством. Этот метод возвращается после того, как все измененные данные и атрибуты этого FileDescriptor были записаны на соответствующие устройства (устройства). В частности, если этот FileDescriptor ссылается на физический носитель данных, такой как файл в файловой системе, синхронизация не вернется, пока все модифицированные копии буферов, связанных с этим FileDesecriptor в памяти, не будут записаны на физический носитель. синхронизация предназначена для использования кодом, который требует, чтобы физическое хранилище (например, файл) находилось в известном состоянии.
Эти два вызова должны быть достаточными. Это? Наверное, это не так.
Фон: я делаю небольшое сравнение производительности (2 ГБ, последовательная запись) с использованием C/Java, а версия Java в два раза быстрее, чем версия C и, вероятно, быстрее, чем аппаратное обеспечение (120 МБ/с на одном HD), Я также попытался выполнить синхронизацию инструмента командной строки с Runtime.getRuntime(). Exec ( "sync" ), но это не изменило поведение.
Код C, приводящий к 70 Мбайт/с (с использованием API низкого уровня (open, write, close), не сильно меняется):
FILE* fp = fopen(filename, "w");
while(xyz) {
fwrite(buffer, 1, BLOCK_SIZE, fp);
}
fflush(fp);
fclose(fp);
sync();
Без окончательного вызова для синхронизации; Я получил нереалистичные ценности (более 1 ГБ, а также производительность основной памяти).
Почему существует такая большая разница между C и Java? Есть две возможности: я не синхронизирую данные корректно в Java или код C является субоптимальным по какой-либо причине.
Обновление: Я сделал strace работает с "strace -cfT cmd". Вот результаты:
C (API низкого уровня): MB/s 67.389782
% time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 87.21 0.200012 200012 1 fdatasync 11.05 0.025345 1 32772 write 1.74 0.004000 4000 1 sync
C (API высокого уровня): MB/s 61.796458
% time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 73.19 0.144009 144009 1 sync 26.81 0.052739 1 65539 write
Java (1.6 SUN JRE, java.io API): MB/s 128.6755466197537
% time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 80.07 105.387609 3215 32776 write 2.58 3.390060 3201 1059 read 0.62 0.815251 815251 1 fsync
Java (1.6 SUN JRE, java.nio API): MB/s 127.45830221558376
5.52 0.980061 490031 2 fsync 1.60 0.284752 9 32774 write 0.00 0.000000 0 80 close
Значения времени представляют собой только системное время и, следовательно, довольно бессмысленны.
Обновление 2: Я перешел на другой сервер, перезагрузился, и я использую новый форматированный ext3. Теперь я получаю только 4% -ные различия между Java и C. Я просто не знаю, что пошло не так. Иногда все странно. Я должен был пробовать измерения с другой системой, прежде чем писать этот вопрос. К сожалению.
Обновление 3: Подводя итог ответам:
- Используйте c.force(true), за которым следует s.getFD(). sync() для Java NIO и s.flush() и s.getFD(). sync() для Java stream API. Для API высокого уровня в C не забудьте синхронизировать. Fflush отправил данные в ОС, но не переносит ваши данные на блок-устройство.
- Используйте strace для анализа системных вызовов, выполненных командой
- Перекрестите свои результаты перед отправкой вопроса.
Обновление 4: Обратите внимание на следующие действия question.