Странное поведение с FileStream.WriteFile - PullRequest
9 голосов
/ 02 февраля 2011

Я работаю над программой, которая делает тяжелый произвольный доступ для чтения / записи для огромного файла (до 64 ГБ). Файлы специально структурированы, и для доступа к ним я создал фреймворк; Через некоторое время я попытался проверить производительность на нем и заметил, что в предварительно выделенных файлах операции последовательной записи выполняются слишком медленно, чтобы быть приемлемыми. После многих тестов я повторил поведение без моей структуры (только методы FileStream); Вот часть кода, которая (с моим оборудованием) повторяет проблему:

FileStream fs = new FileStream("test1.vhd", FileMode.Open);
byte[] buffer = new byte[256 * 1024];
Random rand = new Random();
rand.NextBytes(buffer);
DateTime start, end;
double ellapsed = 0.0;
long startPos, endPos;

BinaryReader br = new BinaryReader(fs);
br.ReadUInt32();
br.ReadUInt32();
for (int i = 0; i < 65536; i++)
    br.ReadUInt16();

br = null;

startPos = 0;   // 0
endPos = 4294967296;    // 4GB
for (long index = startPos; index < endPos; index += buffer.Length)
{
    start = DateTime.Now;
    fs.Write(buffer, 0, buffer.Length);
    end = DateTime.Now;
    ellapsed += (end - start).TotalMilliseconds;
}

К сожалению, проблема кажется непредсказуемой, поэтому иногда она "работает", а иногда нет. Однако, используя Process Monitor, я обнаружил следующие события:

Operation   Result  Detail
WriteFile   SUCCESS Offset: 1.905.655.816, Length: 262.144
WriteFile   SUCCESS Offset: 1.905.917.960, Length: 262.144
WriteFile   SUCCESS Offset: 1.906.180.104, Length: 262.144
WriteFile   SUCCESS Offset: 1.906.442.248, Length: 262.144
WriteFile   SUCCESS Offset: 1.906.704.392, Length: 262.144
WriteFile   SUCCESS Offset: 1.906.966.536, Length: 262.144
ReadFile    SUCCESS Offset: 1.907.228.672, Length: 32.768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
WriteFile   SUCCESS Offset: 1.907.228.680, Length: 262.144
ReadFile    SUCCESS Offset: 1.907.355.648, Length: 32.768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
ReadFile    SUCCESS Offset: 1.907.490.816, Length: 32.768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
WriteFile   SUCCESS Offset: 1.907.490.824, Length: 262.144
ReadFile    SUCCESS Offset: 1.907.617.792, Length: 32.768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
ReadFile    SUCCESS Offset: 1.907.752.960, Length: 32.768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal
WriteFile   SUCCESS Offset: 1.907.752.968, Length: 262.144

То есть после перезаписи почти 2 ГБ, FileStream.Write начинает вызывать ReadFile после каждого WriteFile, и эта проблема продолжается до конца процесса; Кроме того, смещение, с которого начинается проблема, кажется случайным. Я шаг за шагом отлаживал метод FileStream.Write и убедился, что на самом деле это WriteFile (Win32 API), который внутренне вызывает ReadFile.

Последняя заметка; Я не думаю, что это проблема фрагментации файла: я лично дефрагментировал файл с помощью contig!

Ответы [ 2 ]

1 голос
/ 02 февраля 2011

Я нашел это из MSDN. Может ли это быть связано? Мне кажется, у каждого файла есть один глобально общий указатель.

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

http://msdn.microsoft.com/en-us/library/system.io.filestream.aspx

1 голос
/ 02 февраля 2011

Я считаю, что это связано с FileStream.Write / Read и ограничением в 2 ГБ.Вы запускаете это в 32-битном процессе?Я не смог найти какую-либо конкретную документацию по этому вопросу, но вот вопрос MSDN forum , который звучит так же.Вы можете попробовать запустить это в 64-битном процессе.

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

...