FileStream synchronisiert den Dateioffset nicht mehr mit dem Betriebssystem
Zur Leistungsverbesserung synchronisiert FileStream den Dateioffset nicht mehr mit dem Betriebssystem.
Beschreibung der Änderung:
In früheren .NET-Versionen synchronisiert FileStream den Dateioffset mit dem Windows-Betriebssystem, wenn Lese- oder Schreibvorgänge für eine Datei ausgeführt werden. Der Offset wird synchronisiert, indem SetFilePointer aufgerufen wird. Dabei handelt es sich um einen ressourcenintensiven Systemaufruf. Ab .NET 6 synchronisiert FileStream den Dateioffset nicht mehr. Stattdessen wird der Offset nur im Arbeitsspeicher gespeichert. FileStream.Position gibt immer den aktuellen Offset zurück. Wenn Sie jedoch das Dateihandle von FileStream.SafeFileHandle erhalten und das Betriebssystem mithilfe eines Systemaufrufs nach dem aktuellen Dateioffset abfragen, lautet der Offsetwert 0.
Der folgende Code zeigt, wie sich der Dateioffset zwischen früheren .NET-Versionen und .NET 6 unterscheidet.
[DllImport("kernel32.dll")]
private static extern bool SetFilePointerEx(SafeFileHandle hFile, long liDistanceToMove, out long lpNewFilePointer, uint dwMoveMethod);
byte[] bytes = new byte[10_000];
string path = Path.Combine(Path.GetTempPath(), Path.GetTempFileName());
using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, bufferSize: 4096, useAsync: true))
{
SafeFileHandle handle = fs.SafeFileHandle;
await fs.WriteAsync(bytes, 0, bytes.Length);
Console.WriteLine(fs.Position); // 10000 in all versions
if (SetFilePointerEx(handle, 0, out long currentOffset, 1 /* get current offset */))
{
Console.WriteLine(currentOffset); // 10000 in .NET 5, 0 in .NET 6
}
}
Eingeführt in Version
.NET 6
Grund für die Änderung
Diese Änderung wurde eingeführt, um die Leistung asynchroner Lese- und Schreibvorgänge zu verbessern und die folgenden Probleme zu lösen:
- Win32 FileStream veröffentlicht eine Suche bei jedem ReadAsync-Aufruf
- FileStream.Windows useAsync WriteAsync-Aufrufe blockieren APIs
Mit dieser Änderung sind ReadAsync-Vorgänge bis zu zweimal schneller, und WriteAsync-Vorgänge sind bis zu fünfmal schneller.
Empfohlene Maßnahme
Ändern Sie Code, der davon abhing, dass der Offset synchronisiert wird.
Zum Aktivieren des .NET 5-Verhaltens in .NET 6 geben Sie einen
AppContext
-Parameter oder eine Umgebungsvariable an. Indem Sie den Parameter auftrue
festlegen, können Sie alle Leistungsverbesserungen in .NET 6 deaktivieren, die anFileStream
vorgenommen wurden.{ "configProperties": { "System.IO.UseNet5CompatFileStream": true } }
set DOTNET_SYSTEM_IO_USENET5COMPATFILESTREAM=1
Hinweis
Diese Option ist nur in .NET 6 verfügbar. Sie wurde in .NET 7 entfernt.
Betroffene APIs
Keine.