2015-03-12 8 views
7

Poiché devo eseguire molte operazioni di I/O su file nella mia applicazione, , ho deciso di implementarle in modo asincrono. Guardando in MSDN, non ci sono controparti asincrone per File.Create, File.Delete e File.Move. Come ho imparato, il motivo è la non esistenza di un'implementazione asincrona Win32 per eliminazione dei file, creare o spostare, quindi ho finito con la seguente soluzione:Come implementare un file asincrono. Elimina/Crea/Sposta?

public static Task DeleteAsync(string path) 
{ 
    Guard.FileExists(path); 

    return Task.Run(() => File.Delete(path)); 
} 

public static Task<FileStream> CreateAsync(string path) 
{ 
    Guard.IsNotNullOrWhitespace(path); 

    return Task.Run(() => File.Create(path)); 
} 

public static Task MoveAsync(string sourceFileName, string destFileName) 
{ 
    Guard.FileExists(sourceFileName); 
    Guard.IsNotNullOrWhitespace(destFileName); 

    return Task.Run(() => { File.Move(sourceFileName, destFileName); }); 
} 

Considerando il paradigma "Don’t use Task.Run in Libraries", mi chiedo se c'è un migliore implementazione o dovrei ricorrere al codice sincrono?

Molte grazie in anticipo!

Modifiche:


  • Migliorato il codice basato su Pietro Duniho raccomandazione
  • Aggiunto il link al post originale fornito da Sriram Sakthivel
+0

Chi dice "non utilizzare' Task.Run() 'nelle librerie"? Come pensi di poter eseguire i metodi sincroni senza usare quello o qualcosa di simile? C'è qualcosa di veramente sbagliato nell'implementazione che hai? –

+1

@PeterDuniho È la raccomandazione di stephen cleary. Ti consiglia di non utilizzare 'Task.Run' nell'implementazione, se hai bisogno di avvolgere il metodo sincrono come operazione asincrona, quindi fallo nel codice client dove ti serve.Modifica: anche Stephen toub dice che non esporre il wrapper asincrono su metodi sincroni. –

+0

A proposito, le implementazioni sembrano meno che perfette. I metodi dovrebbero tutti solo restituire il 'Task' (senza configurare attendere, e senza che i metodi siano' async'). 'CreateAsync()' può 'restituire Task.Run (() => File.Create (path));' (cioè l'attività attendibile restituita dovrebbe restituire di per sé l'oggetto 'FileStream' ... non è necessario attendere te stesso per farlo , né usare l'acquisizione variabile per realizzarlo). –

risposta

6

Se si deve fare questo, Vorrei scrivere i metodi come questo (nota: prontamente accetto che questo è esattamente ciò che Stephens Cleary e Toub ci stanno esortando a non fare):

public static Task DeleteAsync(string path) 
{ 
    Guard.FileExists(path); 

    return Task.Run(() => { File.Delete(path); }); 
} 

public static Task<FileStream> CreateAsync(string path) 
{ 
    Guard.IsNotNullOrWhitespace(path); 

    return Task.Run(() => File.Create(path)); 
} 

public static Task MoveAsync(string sourceFileName, string destFileName) 
{ 
    Guard.FileExists(sourceFileName); 
    Guard.IsNotNullOrWhitespace(destFileName); 

    return Task.Run(() => { File.Move(sourceFileName, destFileName); }); 
} 

Questo pulisce un po 'il codice ed elimina il contesto eccessivo/il cambio di thread.

Nel contesto di un programma basato su GUI, sembra opportuno utilizzare wrapper come questi. Penso che se non crei un'intera nuova libreria con le API sincrone e asincrone in parallelo, come descritto negli articoli citati, questo non è terribile.

Ma per me, il problema più grande è che nessuna di queste operazioni dovrebbe richiedere abbastanza tempo per giustificare la loro asincronia in primo luogo. Cioè la solita ragione per cui esegui le cose in un Task da un thread dell'interfaccia utente è perché il thread dell'interfaccia utente non può permettersi di aspettare mentre l'operazione viene completata. Ma qui, per ciascuna di queste operazioni, l'operazione di inviare l'operazione al pool di thread e quindi riprendere con la continuazione dopo che è stata eseguita, è probabile che aggiunga al proprio programma un carico di prestazioni pari a quello dell'operazione stessa.

E 'per che motivo che mi consiglia di non disturbare con una versione asincrona dei metodi. Basta chiamare direttamente i metodi Create(), Delete() e Move() dall'interfaccia utente.

(Nota: una sola eccezione a quanto sopra è che se si tratta di una condivisione di rete o di diversi volumi, in cui un Move() comportino dati copiando Quindi, anche lì, è un grande grande "dipende" Allo stesso modo, mentre Delete() e Create().. Normalmente sarebbe veloce anche su una rete, potrebbe richiedere un po 'se l'operazione fallirà davvero.Potresti avere un buon use case per eseguire le operazioni in modo asincrono lì).

+0

Come sidenote, l'uso di 'Guard.FileExists (sourceFileName)' in modo sincrono è probabilmente sbagliato. Se 'sourceFileName' è su un altro computer, che è lento a rispondere, allora sei tornato al punto 0 :-) – xanatos

+0

@xanatos: sì, sono d'accordo anche con quell'osservazione. Senza vedere l'implementazione non è possibile saperlo con certezza, ma sembra logico supporre che si tratti solo della delega a 'File.Exists()' e di un'eccezione se restituisce 'false'. –

+0

@Peter Duniho: In WinRT tutte le operazioni sui file sono asincrone, quindi mi chiedevo se questo non è utile anche per le comuni applicazioni .NET. Ok, un'implementazione asincrona di File.Create è dubbia, ma l'eliminazione e lo spostamento possono essere eseguiti a lungo, anche se l'operazione ha esito positivo. Secondo te, sarebbe un buon approccio implementare semplicemente Move async e Create/Delete in sincrono? – Fabe

Problemi correlati