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.
fonte
2016-06-30 18:11:08
Che cosa fa questo metodo? Qualcosa che blocca la tua interfaccia utente? Quindi la risposta è sì, avviarla in un nuovo compito. –
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
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