2016-05-05 2 views
13

я наткнулся на следующий вопрос при попытке определить, если я использую Stream методы, такие как ReadAsync и CopyToAsync правильно: C# 4.5 file read performance sync vs asyncasync/ожидание и открытие FileStream?

В этом вопросе я прочитал следующее в принятом ответе:

В частности, ваш тест «асинхронный» не использует асинхронный ввод-вывод; с файлом streams, вы должны явно открыть их как асинхронные, иначе вы просто выполняете синхронные операции в фоновом потоке.

В асинхронном коде IO он использовал следующее, чтобы открыть FileStream «асинхронно»:

var file = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true) 

Так мне было интересно, если вы собираетесь использовать такие методы, как CopyToAsync следует ли открыть лежащий в основе FileStream, как показано выше ?, а не делать что-то простое, как следующее:

File.Open(filename, FileMode.Open) 

который, как пример я п фактической документации CopyToAsync демонстрирует открытие основного FileStream: https://msdn.microsoft.com/en-us/library/hh159084(v=vs.110).aspx

Если это не имеет значения, какой путь открыто, лежащие в основе FileStream, что делает параметр FileStream конструктора useAsync делать?

ответ

8

Так что мне было интересно, если вы намереваетесь использовать такие методы, как CopyToAsync, следует ли вам открыть базовый FileStream, как показано выше?

Да. Причина в основном историческая.

Во-первых, в Windows, HANDLEs (including file handles) must be opened/created explicitly with an asynchronous flag if you want to do asynchronous (OVERLAPPED) operations on them.

Однако the old Windows 95/98/ME line only supported asynchronous operations on serial port and IOCTL (device driver) handles. Асинхронный ввод-вывод на дисковых файлах не поддерживался на этой платформе. И the original .NET did support 98/ME, поэтому оригинал FileStream просто использовал синхронный ввод-вывод. I думаю, (но я не совсем уверен), что APM methods (например, FileStream.BeginRead) на Win98/ME, вероятно, только что реализован с использованием так называемого "asynchronous delegates" (который просто выполняет синхронный метод, такой как FileStream.Read в потоке пула потоков).

Итак, это историческая причина, по которой ручки файлового потока были , а не, которые были открыты с асинхронным флагом по умолчанию.

Который, как пример в реальной документации CopyToAsync демонстрирует

К сожалению, много примеров MSDN довольно низкого качества. Они в порядке, если вы подходите к ним с точки зрения «вот пример того, как назвать этот конкретный метод», но не настолько велики с точки зрения «вот пример кода производственного качества, который использует этот метод».

1

сайт MSDN говоря

useAsync Указывает, следует ли использовать асинхронный ввод/вывод или синхронного ввода/вывода. Однако обратите внимание, что базовая операционная система может не поддерживать асинхронный ввод-вывод, поэтому при указании истины дескриптор может быть открыт синхронно в зависимости от платформы. При асинхронном открытии методы BeginRead и BeginWrite работают лучше при больших чтениях или записи, но для небольших чтений или записи они могут быть намного медленнее. Если приложение предназначено для использования асинхронного ввода-вывода, установите для параметра useAsync значение true. С помощью асинхронного ввода/вывода правильно может ускорить работу приложений от столько, сколько в 10 раз, но использовать его без реорганизации приложения для асинхронного ввода/вывода может привести к снижению производительности на целых фактор 10.

+0

Так что это не имеет значения для других асинхронных методов ввода-вывода, таких как CopyToAsync? –

+0

Да, вопрос для других асинхронных методов ввода-вывода, таких как CopyToAsync. но, к сожалению, высказывание MSDN не имеет значения. –

6

So Мне было интересно, собираетесь ли вы использовать такие методы, как CopyToAsync, следует ли открывать базовый FileStream, как показано выше, а не делать что-то простое, например File.Open?

Я использовал ILSpy для декомпиляции и просмотра File.Open.

public static FileStream Open(string path, FileMode mode) 
{ 
    return File.Open(path, 
        mode, 
        (mode == FileMode.Append) 
         ? FileAccess.Write 
         : FileAccess.ReadWrite, 
        FileShare.None); 
} 

Который называет это:

public static FileStream Open(string path, FileMode mode, FileAccess access, FileShare share) 
{ 
    return new FileStream(path, mode, access, share); 
} 

И этот конкретный FileStream конструктор переходит в false для параметра useAsync. Итак, да, похоже, это имеет значение. Однако вы все равно можете использовать API async, и он все равно будет работать так, как вы ожидали.

Как Ганс Passant гласит:

Базовым CreateFile() вызова затем использует параметр FILE_FLAG_OVERLAPPED. Это позволяет перекрывать I/O, механизм, который позволяет асинхронные чтения и записи на уровне winapi.

FileStream класс имеет _isAsync логическое значение, и это означает, что «Если асинхронной IO не поддерживается на этой платформе, или если это FileStream не был открыт с FileOptions.Asynchronous.».

Опять же, вы по-прежнему получаете Task, который представляет собой асинхронную операцию по вашему желанию.

+1

Зачем использовать декомпилятор, когда [вы действительно можете посмотреть на источник] (http://referencesource.microsoft.com/#mscorlib/system/io/file.cs,1a53662a82db3651)? – svick

+0

Источник ссылки замечательный, и я все время использую его, но какая гарантия, что это обновление на сегодняшний день? На самом деле я не знаю ... в любом случае приводит к ответу. –

+0

В нем говорится, что он показывает источник .Net Framework 4.6.1, который должен быть достаточно недавним. – svick

Смежные вопросы