Pracuję nad programem, który ma duży dostęp do odczytu/zapisu na dużym pliku (do 64 GB). Pliki są ustrukturyzowane i aby uzyskać do nich dostęp, stworzyłem framework; po pewnym czasie próbowałem przetestować na nim wydajność i zauważyłem, że w przypadku wcześniej przydzielonych plików sekwencyjne operacje zapisu są zbyt wolne, aby można je było zaakceptować. Po wielu testach replikowałem zachowanie bez mojego frameworka (tylko metody FileStream); oto fragment kodu (z mojego sprzętu) replikuje problem:Dziwne zachowanie z 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;
}
Niestety problem wydaje się być nieprzewidywalne, więc czasami to „działa”, czasami nie. Jednak użycie Process Monitor Złapałem następujące zdarzenia:
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
Oznacza to, że po ponad pisanie prawie 2 GB FileStream.Write
rozpoczyna zadzwonić ReadFile
po każdym WriteFile
i ten problem w dalszym ciągu aż do końca proces; również przesunięcie, od którego zaczyna się problem, wydaje się przypadkowe. Przeprowadziłem debugowanie krok po kroku wewnątrz metody FileStream.Write
i sprawdziłem, czy faktycznie jest to WriteFile
(Win32 API), który wewnętrznie wywołuje ReadFile
.
Ostatnia uwaga; Nie sądzę, że jest to problem fragmentacji plików: osobiście zdefragmentowałem plik za pomocą contig!
Rozważyć pamięci przełączania [odwzorowanych Files] (http://msdn.microsoft.com/en-us/library/dd997372.aspx). – gor
Masz na myśli, że powinienem utworzyć referencje z Win32 API lub korzystać z .NET4? W pierwszym przypadku lepiej będzie stworzyć całe środowisko w C/C++ (i naprawdę rozważam taką możliwość!); w tym ostatnim powinienem również uaktualnić do VS2010 lub użyć SharpDevelop: wolę używać tego, co mam! – Atropo
Może to być problem z buforowaniem systemu operacyjnego, nie mogę replikować odczytów na Win7 x64 i .Net 4.0. (Użyj też bloków 'using', nie chcę dzisiaj płakać) – user7116