К сожалению, встроенные асинхронные API-интерфейсы для доступа к файловой системе не реализованы последовательно в соответствии с собственными рекомендациями Microsoft о том, как должны вести себя асинхронные методы.
Асинхронный метод основанный на TAP, может выполнять небольшой объем работы синхронно, например проверять аргументы и запускать асинхронную операцию, прежде чем он вернет результирующую задачу. Синхронная работа должна быть сведена к минимуму, чтобы асинхронный метод мог быстро возвращаться.
Такие методы, как StreamReader.ReadToEndAsync
, не ведут себя таким образом и вместо этого блокируют текущий поток для значительное количество времени, прежде чем вернуть неполный Task
. Например, в моем более старом эксперименте с чтением файла размером 6 МБ с моего SSD этот метод блокировал вызывающий поток на 120 мс c, возвращая Task
, который затем был завершен только через 20 мс c. Мое предложение - избегать использования API-интерфейсов асинхронной файловой системы из приложений GUI и использовать вместо них синхронные API-интерфейсы, заключенные в Task.Run
.
var lines = await Task.Run(() => File.ReadAllLines(@"D:\temp.txt"));
Обновление: Вот некоторые экспериментальные результаты с File.ReadAllLinesAsync
:
var stopwatch = Stopwatch.StartNew();
var task = File.ReadAllLinesAsync(@"C:\6MBfile.txt");
var duration1 = stopwatch.ElapsedMilliseconds;
bool isCompleted = task.IsCompleted;
stopwatch.Restart();
var lines = await task;
var duration2 = stopwatch.ElapsedMilliseconds;
Console.WriteLine($"Create: {duration1:#,0} msec, Task.IsCompleted: {isCompleted}");
Console.WriteLine($"Await: {duration2:#,0} msec, Lines: {lines.Length:#,0}");
Вывод:
Create: 450 msec, Task.IsCompleted: False
Await: 5 msec, Lines: 204,000
Метод File.ReadAllLinesAsync
заблокировал текущий поток на 450 мс c, а возвращенная задача завершилась через 5 мс c. Эти измерения согласованы после нескольких запусков.
. NET Core 3.1.3, C# 8, консольное приложение, сборка выпуска (отладчик не подключен), Windows 10, SSD Toshiba OCZ Ar c 100 240 ГБ