2016-05-05 30 views
13

mi sono imbattuto nel seguente questione quando si cerca di determinare se stavo usando le Stream metodi come ReadAsync e CopyToAsync correttamente: C# 4.5 file read performance sync vs asyncasync/attende e apre un FileStream?

In questa domanda che ho letto quanto segue nella risposta accettata:

In particolare, il test "asincrono" non utilizza l'I/O asincrono; con i file flussi, devi aprirli esplicitamente come asincroni oppure stai semplicemente eseguendo operazioni sincrone su un thread in background.

Nel suo codice IO asincrono che stava usando il seguente per aprire il FileStream 'asincrono':

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

quindi mi chiedevo se avete intenzione di usare metodi come CopyToAsync se si dovrebbe aprire la sottostante FileStream come indicato sopra ?, invece di fare qualcosa di semplice come il seguente:

File.Open(filename, FileMode.Open) 

che è come l'esempio che ho n la documentazione reale per CopyToAsync dimostra l'apertura del sottostante FileStream: https://msdn.microsoft.com/en-us/library/hh159084(v=vs.110).aspx

Se non importa in che modo il sottostante FileStream si apre, che cosa fa il parametro useAsync del costruttore FileStream fare?

risposta

8

Quindi mi chiedevo se si intende utilizzare metodi come CopyToAsync se è necessario aprire il FileStream sottostante come mostrato sopra?

Sì. La ragione è per lo più storica.

Primo, su Windows, HANDLEs (including file handles) must be opened/created explicitly with an asynchronous flag if you want to do asynchronous (OVERLAPPED) operations on them.

Tuttavia, the old Windows 95/98/ME line only supported asynchronous operations on serial port and IOCTL (device driver) handles. L'I/O asincrono sui file del disco non era supportato su quella linea di piattaforma. E the original .NET did support 98/ME, quindi l'originale FileStream utilizzava solo I/O sincrono. I penso che (ma non sono assolutamente sicuro) che APM methods (come FileStream.BeginRead) su Win98/ME sono stati probabilmente implementati utilizzando il cosiddetto "asynchronous delegates" (che esegue solo un metodo sincrono come FileStream.Read su un thread di thread).

Quindi, questo è il motivo storico per cui gli handle del flusso di file erano non aperti con il flag asincrono per impostazione predefinita.

che è come l'esempio nella documentazione reale per copyToAsync dimostra

Purtroppo, un sacco di esempi MSDN sono di qualità piuttosto scarsa. Sono OK se li avvicini dal punto di vista di "ecco un esempio di come chiamare questo metodo specifico", ma non così grandi dal punto di vista di "ecco un esempio di codice di qualità di produzione che utilizza questo metodo".

1

sito Web MSDN dicendo

useAsync Specifica se utilizzare I/O asincrono o sincrono I/O. Tuttavia, si noti che il sistema operativo sottostante potrebbe non supportare l'I/O asincrono, pertanto, quando si specifica true, l'handle potrebbe essere aperto in modo sincrono a seconda della piattaforma. Se aperti in modo asincrono, i metodi-e BeginWrite funzionano meglio su letture o scritture di grandi dimensioni, ma potrebbero essere molto più lenti per letture o scritture di piccole dimensioni. Se l'applicazione è progettata per sfruttare l'I/O asincrono, impostare il parametro useAsync su true. Utilizzo I/O asincrono correttamente può accelerare applicazioni di quanto un fattore di 10, ma il suo utilizzo senza riprogettare la domanda di I/O asincrono può ridurre le prestazioni anche del fattore di 10.

+0

Quindi non importa per altri metodi IO asincroni come CopyToAsync? –

+0

Sì, importa per altri metodi IO asincroni come CopyToAsync. ma Sfortunatamente, MSDN dice non importa. –

6

Così Mi stavo chiedendo se intendi utilizzare metodi come CopyToAsync se dovresti aprire il FileStream sottostante come mostrato sopra, invece di fare qualcosa di semplice come File.Open?

Ho usato ILSpy per decompilare e guardare File.Open.

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

che chiama questo:

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

E questo specifico FileStream costruttore passa in false per il parametro useAsync. Quindi, sì, sembra che importi. Tuttavia, puoi comunque richiamare le APIe funzionerà come previsto.

Come Hans Passant afferma:

Il sottostante CreateFile() chiamata quindi utilizza l'opzione FILE_FLAG_OVERLAPPED. Ciò consente sovrapposizioni di I/O, un meccanismo che consente di leggere e scrivere asincroni a livello winapi.

La classe FileStream ha un _isAsync bool, e significa "Se async non è supportato su questa piattaforma o se questo FileStream non è stato aperto con FileOptions.Asynchronous.".

Ancora, si ottiene ancora un Task che rappresenta quell'operazione asincrona come si desidera.

+1

Perché utilizzare un decompilatore quando [si può effettivamente guardare la fonte] (http://referencesource.microsoft.com/#mscorlib/system/io/file.cs.1a53662a82db3651)? – svick

+0

La fonte di riferimento è ottima e io la uso sempre, ma che garanzia c'è che sia l'aggiornamento aggiornato? In realtà non lo so ... in entrambi i casi porta a una risposta. –

+0

Dice che mostra il sorgente per .Net Framework 4.6.1, che dovrebbe essere abbastanza recente. – svick