2014-12-08 14 views
13

Il vecchio modo .Net di eseguire l'I/O asincrono per un FileStream è quello di utilizzare FileStream.BeginRead() e FileStream.EndRead().Quando si utilizza FileStream.ReadAsync() dovrei aprire il file in modalità asincrona?

La documentazione MSDN per FileStream.BeginRead() paese:

FileStream fornisce due diverse modalità di funzionamento: sincrono I/O e I/O asincrono. Mentre è possibile utilizzare entrambi, le risorse del sistema operativo sottostante potrebbero consentire l'accesso solo in una di queste modalità.

Per impostazione predefinita, FileStream apre l'handle del sistema operativo in modo sincrono. In Windows, questo rallenta i metodi asincroni. Se vengono utilizzati metodi asincroni, utilizzare il costruttore FileStream (String, FileMode, FileAccess, FileShare, Int32, Boolean).

Il .Net 4.5x modo di eseguire asincrono I/O per un FileStream è quello di utilizzare Stream.ReadAsync().

La documentazione MSDN per FileStream.ReadAsync() collega direttamente alla documentazione per Stream.ReadAsync(). Questa documentazione non menziona alcuna necessità di aprire il file in modalità asincrona; in effetti, il codice di esempio nella documentazione non lo fa in modo evidente.

Pertanto, suppongo che quando si utilizza File.ReadAsync() non sia necessario aprire il file in modalità asincrona.

Questa supposizione è corretta?

[EDIT]

Ho appena scoperto an MSDN article on using Async for File Access.

Questo afferma:

Gli esempi in questo argomento utilizzano la classe FileStream, che ha un'opzione che causa I/O asincrono a verificarsi a livello di sistema operativo. Usando questa opzione, puoi evitare di bloccare un thread ThreadPool in molti casi.

Per abilitare questa opzione, si specifica useAsync = true o options = FileOptions.Asynchronous argument nella chiamata del costruttore.

Così ora sto pensando che io dovrei essere aprire il file in modalità asincrona ... Se è così, è un po 'un peccato che il codice di esempio fornito nella documentazione per ReadAsync() fa non aprire il file in modo asincrono!

risposta

15

In win32, è necessario specificare FILE_FLAG_OVERLAPPED per utilizzare file IO asincrono. Nel mondo .net si usa il parametro isAsync di FileStream per ottenere lo stesso risultato. Se non si riesce a farlo, le operazioni non saranno asincrone.

È un peccato che FileStream.ReadAsync e i relativi metodi non siano riusciti a documentarlo.

È possibile confermare questo sbirciando nell'implementazione.

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 finirà per chiamare per Stream.Read metodo sincrono nel ThreadPool dando l'impressione che il movimento sia asincrona, ma in realtà non.

Informazioni correlate da Concurrent Programming On Windows libro (Pg: 818):

Come con CreateFile, è necessario specificare al momento della creazione che ci si desidera utilizzare un FileStream per l'esecuzione asincrona. Con FileStream, si esegue questa operazione passando true come argomento isAsync a overload di costruttore, che lo accettano. La proprietà dello stream restituirà quindi true. Se non si riesce a superare questo valore , le chiamate a e BeginWrite avranno esito positivo. Ma loro userà l'implementazione della classe base da Stream, che fornisce nessuno dei vantaggi dell'efflato I/O asincrono dei file.

Le informazioni di cui sopra riguardano i metodi APM (poiché si tratta di un vecchio libro) ma ancora pertinenti.

+1

Questo è molto importante sapere! Sembrano esserci molte pagine web che discutono di 'ReadAsync()' ma non menzionano questo fatto molto importante (ad esempio, http://www.dotnetperls.com/async) –

+0

Sì, il sito web che hai collegato è piuttosto buono ma purtroppo non è riuscito a parlarne. Vedo che il link dice con async che stiamo usando solo thread singolo e mostra un esempio con il lettore di stream. Questo è sbagliato perché l'implementazione avviene usando 'ThreadPool' senza il flag' isAsync' :( –