Sto lavorando a un programma che esegue pesanti accessi in lettura/scrittura su file enormi (fino a 64 GB). I file sono strutturati in modo specifico e per accedervi ho creato un framework; dopo un po 'ho provato a testare le prestazioni su di esso e ho notato che le operazioni di scrittura sequenziali di file preallocato sono troppo lente per essere accettabili. Dopo molti test ho replicato il comportamento senza il mio framework (solo i metodi FileStream); qui è la parte di codice che (con il mio hardware) replica il problema:Strano comportamento con FileStream.WriteFile
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;
}
Purtroppo il problema sembra essere imprevedibile, così a volte "funziona", a volte non è così. Tuttavia, utilizzando Process Monitor ho preso i seguenti eventi:
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
Cioè, dopo oltre-scrittura quasi 2 GB, FileStream.Write
inizia a chiamare ReadFile
dopo ogni WriteFile
, e questo numero continuerà fino alla fine del processi; inoltre, l'offset a cui inizia il problema sembra essere casuale. Ho eseguito il debug passo dopo passo all'interno del metodo FileStream.Write
e ho verificato che sia effettivamente lo WriteFile
(API Win32) che, internamente, chiama ReadFile
.
Ultima nota; Non penso che sia un problema di frammentazione dei file: ho deframmentato il file personalmente con contig!
consideri memoria commutazione [file mappati] (http://msdn.microsoft.com/en-us/library/dd997372.aspx). – gor
Vuoi dire che dovrei creare riferimenti da API Win32 o utilizzare .NET4? Nel primo caso, sarà meglio creare l'intero framework in C/C++ (e sto davvero considerando questa possibilità!); nel secondo dovrei anche aggiornare a VS2010 o usare SharpDevelop: preferisco usare quello che ho! – Atropo
Potrebbe trattarsi di un problema di buffering del sistema operativo, non riesco a replicare le letture su Win7 x64 e .Net 4.0. (Inoltre, per favore usa i blocchi 'using', non voglio piangere oggi) – user7116