que - task await c# ejemplo
async/await y abriendo un FileStream? (3)
Encontré la siguiente pregunta cuando ReadAsync
determinar si estaba usando los métodos de ReadAsync
como ReadAsync
y CopyToAsync
correctamente: C # 4.5 rendimiento de lectura de lectura sincronización contra asíncrono
En esta pregunta leí lo siguiente en la respuesta aceptada:
En particular, su prueba "asíncrona" no usa E / S asíncrona; con los flujos de archivos, tiene que abrirlos explícitamente como asíncronos o, de lo contrario, solo está realizando operaciones síncronas en un hilo de fondo.
En su código de E / S asíncrono, estaba usando lo siguiente para abrir FileStream
''asincrónicamente'':
var file = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true)
Así que me preguntaba si pretendes usar métodos como CopyToAsync
si deberías abrir el FileStream
subyacente como se muestra arriba, en lugar de hacer algo simple como lo siguiente:
File.Open(filename, FileMode.Open)
Así es como el ejemplo en la documentación real para CopyToAsync
demuestra CopyToAsync
abrir el FileStream
subyacente: https://msdn.microsoft.com/en-us/library/hh159084(v=vs.110).aspx
Si no importa de qué manera se abre el FileStream
subyacente, ¿qué hace el parámetro useAsync
del constructor FileStream
?
Así que me preguntaba si pretendes usar métodos como CopyToAsync si deberías abrir el FileStream subyacente como se muestra arriba, en lugar de hacer algo simple como
File.Open
?
Usé ILSpy para descompilar y mirar File.Open
.
public static FileStream Open(string path, FileMode mode)
{
return File.Open(path,
mode,
(mode == FileMode.Append)
? FileAccess.Write
: FileAccess.ReadWrite,
FileShare.None);
}
Que llama a esto:
public static FileStream Open(string path, FileMode mode, FileAccess access, FileShare share)
{
return new FileStream(path, mode, access, share);
}
Y este constructor de FileStream
específico pasa en false
para el parámetro useAsync
. Entonces, sí parece importar. Sin embargo, aún puede invocar las API async
y seguirá funcionando como cabría esperar.
Como dice Hans Passant:
La llamada subyacente a
CreateFile()
luego usa la opciónFILE_FLAG_OVERLAPPED
. Esto permite la E / S superpuesta, un mecanismo que permite lecturas y escrituras asíncronas en el nivel de winapi.
La clase FileStream
tiene un bool _isAsync
, y significa "Si no se admite el IO asíncrono en esta plataforma o si este FileStream no se abrió con FileOptions.Asynchronous.".
Nuevamente, aún obtienes una Task
que representa esa operación asíncrona como deseas.
Así que me preguntaba si tiene la intención de utilizar métodos como CopyToAsync si debería abrir el FileStream subyacente como se muestra arriba.
Sí. La razón es sobre todo histórica.
Primero, en Windows, los HANDLE
s (incluidos los manejadores de archivos) deben abrirse / crearse explícitamente con un indicador asíncrono si desea realizar operaciones asincrónicas ( OVERLAPPED
) en ellos .
Sin embargo, la antigua línea de Windows 95/98 / ME solo admitía operaciones asíncronas en el puerto serie y los controladores IOCTL (controlador de dispositivo) . La E / S asíncrona en los archivos de disco no era compatible con esa línea de plataforma. Y el .NET original era compatible con 98 / ME , por lo que el FileStream
original solo usaba E / S síncrona. Creo (pero no estoy absolutamente seguro) que los métodos APM (como FileStream.BeginRead
) en Win98 / ME probablemente se implementaron usando los llamados "delegados asíncronos" (que simplemente ejecutan un método sincrónico como FileStream.Read
en un grupo de subprocesos hilo).
Por lo tanto, esa es la razón histórica por la que los manejadores de archivos no se abrieron con el indicador asíncrono de forma predeterminada.
Que es como el ejemplo en la documentación real para CopyToAsync demuestra
Desafortunadamente, muchos de los ejemplos de MSDN son de baja calidad. Están bien si te acercas a ellos desde la perspectiva de "aquí hay un ejemplo de cómo llamar a este método específico", pero no tanto desde la perspectiva de "aquí hay un ejemplo de código de calidad de producción que utiliza este método".
El sitio web de MSDN dice:
useAsync
Tipo:
System.Boolean
Especifica si se debe utilizar E / S asíncrona o E / S síncrona. Sin embargo, tenga en cuenta que es posible que el sistema operativo subyacente no admita la E / S asíncrona, por lo que, al especificar
true
, el identificador podría abrirse de forma síncrona según la plataforma. Cuando se abren de forma asíncrona, los métodos BeginRead y BeginWrite funcionan mejor en lecturas o escrituras grandes, pero pueden ser mucho más lentos para las lecturas o escrituras pequeñas. Si la aplicación está diseñada para aprovechar las ventajas de la E / S asíncrona, establezca el parámetrouseAsync
entrue
. Usar la E / S asíncrona correctamente puede acelerar las aplicaciones hasta en un factor de 10, pero usarla sin rediseñar la aplicación para la E / S asíncrona puede disminuir el rendimiento hasta en un factor de 10.