При использовании FileStream.ReadAsync() следует открыть файл в режиме async?
Старый .Net способ выполнения асинхронного ввода-вывода для FileStream
заключается в использовании FileStream.BeginRead()
и FileStream.EndRead()
.
Документация MSDN для FileStream.BeginRead()
гласит:
FileStream предоставляет два разных режима работы: синхронный ввод-вывод и асинхронный ввод-вывод. Хотя любой из них может быть использован, базовые ресурсы операционной системы могут позволить доступ только в одном из этих режимов.
По умолчанию FileStream синхронно открывает дескриптор операционной системы. В Windows это замедляет асинхронные методы. Если используются асинхронные методы, используйте конструктор FileStream (String, FileMode, FileAccess, FileShare, Int32, Boolean).
Способ .Net 4.5x
для асинхронного ввода-вывода для FileStream
заключается в использовании Stream.ReadAsync()
.
Документация MSDN для FileStream.ReadAsync()
связана непосредственно с документацией для Stream.ReadAsync()
. В этой документации нет необходимости открывать файл в режиме async; действительно, пример кода в документации явно не делает этого.
Поэтому я предполагаю, что при использовании File.ReadAsync()
нет необходимости открывать файл в асинхронном режиме.
Правильно ли это предположение?
[EDIT]
Я только что обнаружил статью MSDN об использовании Async для доступа к файлам.
Это означает:
В примерах в этом разделе используется класс FileStream, который имеет параметр, который вызывает асинхронный ввод-вывод на уровне операционной системы. Используя эту опцию, во многих случаях можно избежать блокировки потока ThreadPool.
Чтобы включить эту опцию, вы указываете useAsync = true или options = FileOptions.Asynchronous аргумент в вызове конструктора.
Итак, теперь я думаю, что я должен открыть файл в асинхронном режиме... Если это так, то несколько неудачно, что пример кода, приведенный в документации для ReadAsync()
, не открывает файл асинхронно!
Ответы
Ответ 1
В win32 вам нужно указать FILE_FLAG_OVERLAPPED, чтобы использовать асинхронный File IO. В мире .net вы используете параметр isAsync
FileStream
для достижения того же. Если вы этого не сделаете, операции не будут асинхронными.
Жаль, что FileStream.ReadAsync
и связанные с ним методы не смогли его документировать.
Вы можете подтвердить это, заглянув в реализацию.
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
...
if (!this._isAsync || !Environment.IsWindowsVistaOrAbove)
{
return base.ReadAsync(buffer, offset, count, cancellationToken);
}
...
return stateObject;
}
base.ReadAsync
в конечном итоге вызовет метод Stream.Read
синхронно в ThreadPool
, показывая, что операция isync, но на самом деле нет.
Дополнительная информация из Параллельное программирование в Windows (стр. 818):
Как и в случае с CreateFile
, во время создания необходимо указать, что вы как использовать FileStream для асинхронного выполнения. С FileStream
, вы делаете это, передавая true как аргумент isAsync
для перегрузки конструктора, которые его принимают. Поток isAsync
свойство впоследствии вернет true. Если вы не пройдете этот значение, вызовы BeginRead
и BeginWrite
будут успешными. Но они будет использовать реализацию базового класса из Stream, которая обеспечивает ни одно из преимуществ истинного асинхронного ввода-вывода файлов.
Выше информация о методах APM (так как это старая книга), но все еще актуальна.