Description
Description
Calls to both new System.IO.FilesStream(... async: true) and Systeml.IO.ReadAllBytesAsync() both execute synchronously on windows. On Linux they work as expected. This behaviour was replicated on .NET 6, .NET 8 and .NET Framework 4.7.2 on windows and replicated to work correctly on linux on .NET 8. On Windows, this was tested on two machines:
- a desktop machine with a local SSD
- A Citrix VDI with a NAS C drive (however windows believes it is a local drive, not a network drive)
The same behaviour was seen in both.
On linux, this was tested on a laptop with a local NVMe SSD.
The bug is very easy to replicate, with code below which is based on https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/using-async-for-file-access#parallel-asynchronous-io
Reproduction Steps
Run this code:
public static async Task SimpleParallelWriteByteAsync()
{
var rootFilePath = "C:/temp/asynctest2";
var fileSize = 1024 * 1024 * 100;
if (Directory.Exists(rootFilePath))
Directory.Delete(rootFilePath, true);
Directory.CreateDirectory(rootFilePath);
var buffer = new byte[fileSize];
new Random().NextBytes(buffer);
IList<Task> writeTaskList = new List<Task>();
Stopwatch sw = Stopwatch.StartNew();
for (int index = 0; index <= 10; index += 1)
{
string fileName = $"file-{index:00}.txt";
string filePath = Path.Combine(rootFilePath, fileName);
writeTaskList.Add(File.WriteAllBytesAsync(filePath, buffer));
}
var timespanLoop = sw.Elapsed;
await Task.WhenAll(writeTaskList);
var timespanAfterWhenall = sw.Elapsed;
Console.WriteLine($"loop {timespanLoop} after when all {timespanAfterWhenall}");
}
Expected behavior
The expected behaviour is that the loop should finish very rapidly, as the main chunk of IO has not started yet, just been queued by the operating system. The bulk of the work should happen in the operating system IO system, and the C# program should spend most of the time in await Task.WhenAll. This is what happens on linux:
oop 00:00:00.0082008 after when all 00:00:03.0910144
Actual behavior
On several machines on windows, I got:
00:00:05.6234609 after when all 00:00:05.6254815
Note the the lack of time spent in Task.WhenAll, which implies the work is getting done synchronously. This is further confirmed that replacing the await with:
writeTaskList.Add(Task.Run(() => File.WriteAllBytesAsync(filePath, buffer)));
Indeed makes the difference appear with:
loop 00:00:00.0089046 after when all 00:00:01.2339927
Regression?
This appears to have never worked, with the same behaviour on .NET Framework 4.7.2, .NET 6 and .NET 8 so is not a regression.
Known Workarounds
Use Linux.
Configuration
Confirmed to not work on Windows Citrix VDI on .NET 8, .NET 6 and .NET Framework 4.7.2. Confirmed to not work on .NET 6 on a Windows Desktop. Both x64.
Confirmed to work on linux .NET 8.0 Debian 12 x64.
Other information
Originally I believed it might be a windows configuration. However I posted here https://stackoverflow.com/questions/78036177/async-io-executing-synchronously and it appears others replicate the same behaviour!