2016-06-30 33 views
5

Ho letto molti articoli sulla programmazione asincrona, ma non sono sicuro di una cosa. Ho una libreria winrt di terze parti, scritta in C++ e voglio wrapparlo. Così ora ho:Utilizzo di Task.Run per il metodo sincrono in servizio

public Task LoginAsync(){ 
return Task.Run(winrtLibrary.Login();) 
} 

Secondo Stephen Cleary e Stephen Toub blog, non è una buona soluzione. Ma quando uso il metodo in modo sincrono, la mia interfaccia utente non risponderà e verrà bloccata. È meglio esporre il metodo di servizio in modo sincrono e nell'interfaccia utente utilizzare Task.Run?

+0

Che cosa fa questo metodo? Qualcosa che blocca la tua interfaccia utente? Quindi la risposta è sì, avviarla in un nuovo compito. –

+0

Sì, il metodo di accesso può essere di lunga durata.Dipende dalla rete, ecc. Se blocco l'interfaccia utente, non posso annullare la procedura di accesso. – JuP

+1

Il punto che Stephen Cleary ha fatto è che 'Task.Run'" spreca "una discussione per lavorare, e i thread sono costosi. Tuttavia la tua libreria C++ RICHIEDE una discussione per funzionare. Quindi il problema non è tanto che 'Task.Run' è malvagio. Ma 'Task.Run' in genere nasconde il problema di affidarsi ai thread. – Aron

risposta

3

Cosa Stephen Toub significa da

non utilizzare Task.Run nella realizzazione del metodo; invece, utilizzare Task.Run per chiamare il metodo

è che non si dovrebbe usare Task.Run per nascondere CPU lavoro legate dietro metodi asincroni (Task metodi di ritorno). Se è necessario avvolgere codice esterno, nasconderlo dietro un'interfaccia che riflette ciò che questo codice fa. Qualsiasi I/O asincrono può (e deve) essere esposto come metodi di restituzione Task e il lavoro associato alla CPU deve essere esposto con l'API corretta. Consenti ai consumatori del tuo codice di decidere autonomamente come utilizzare quel codice. Quando capita anche al consumatore, usa Task.Run per eseguire il tuo codice sincrono (ora spostato ed esposto tramite interfaccia) dove è molto chiaro che stai scaricando il lavoro con CPU. Nelle app dell'interfaccia utente, ad esempio, dovresti chiamare Task.Run nel tuo livello di interfaccia utente (e non in profondità nei livelli BL o anche DA), in cui è molto chiaro che l'interfaccia utente offra parte del lavoro associato alla CPU.


Perché pensi, che non si deve dire in Task.Run BL? Cosa succede se ho il ViewModel , che fa riferimento al livello di servizio dei riferimenti BL e BL (nel mio caso è wrapper).

Penso che una firma del metodo dovrebbe riflettere esattamente ciò che fa il metodo. Il meglio che posso fare è di reindirizzare indietro alla Cleary's article:

Quando uno sviluppatore vede due metodi in un'API winrtLibrary.Login() e winrtLibrary.LoginAsync(), la convenzione è che essi rappresentano un modo naturale -asynchronous funzionamento. In altre parole, lo sviluppatore si aspetta che winrtLibrary.LoginAsync() sia l'implementazione "naturale" e che winrtLibrary.Login() sia essenzialmente un equivalente sincrono (bloccante) di tale operazione. Tale API implica che winrtLibrary.Login ad un certo punto avrà il thread chiamante immettere uno stato di attesa mentre blocca l'operazione naturalmente asincrona a completa.

È ancora possibile nascondere il codice sincrono dietro metodo asincrono e seguire regola empirica di Cleary, se ti iscrivi il tuo metodo come public Task OffloadLoginToTheThreadPool(). Ma penso (e apparentemente anche a Cleary) che l'alternativa di chiamare semplicemente Task.Run dall'interfaccia utente (o dal controller) sia un approccio molto migliore, e segue i principi di Clean Code.

+0

Perché pensi che non dovrei chiamare Task.Run in BL? Cosa succede se ho ViewModel, che fa riferimento a BL e BL fa riferimento al livello di servizio (nel mio caso è wrapper). – JuP

Problemi correlati