2015-09-15 13 views
9

Właśnie natknąłem niektórych kodu, takich jak:używa `` async` lambda z `Task.Run()` redundantny?

var task = Task.Run(async() => { await Foo.StartAsync(); }); 
task.Wait(); 

(nie, ja nie wiem centrach funkcjonowanie Foo.StartAsync()). Moją pierwszą reakcją będzie pozbyć async/await i przepisać jako:

var task = Foo.StartAsync(); 
task.Wait(); 

byłoby to słuszne, czy też nie (ponownie, wiedząc nic o Foo.StartAsync()). This Odpowiedź na What difference does it make - running an 'async' action delegate with a Task.Run ... wydaje się wskazywać, że mogą być przypadki, kiedy może to mieć sens, ale mówi również "Prawdę mówiąc, nie widziałem tak wielu scenariuszy ..."

+2

W obu przypadkach należy "poczekać" na zadanie zamiast czekać synchronicznie z 'Task.Wait'. – i3arnon

Odpowiedz

10

Normalnie The przeznaczone wykorzystanie dla Task.Run jest wykonanie CPU-związany kod na wątku non-UI. W związku z tym dość rzadko można go używać z delegatem async, ale jest to możliwe (np. Dla kodu, który ma zarówno asynchroniczne, jak i związane z procesorem fragmenty).

Jest to jednak zamierzone użycie. Myślę, że w przykładzie:

var task = Task.Run(async() => { await Foo.StartAsync(); }); 
task.Wait(); 

Jest to o wiele bardziej prawdopodobne, że pierwotny autor stara się synchronicznie zablokować na kod asynchroniczny i jest (ab) używając Task.Run do avoid deadlocks common in that situation (jak opisano na moim blogu).

Zasadniczo wygląda to jak "włamanie do puli wątków", które opisuję w moim article on brownfield asynchronous code.

najlepszym rozwiązaniem jest, aby nie używać Task.RunlubWait:

await Foo.StartAsync(); 

Spowoduje async rosnąć dzięki swojej bazie kodu, który jest najlepszym rozwiązaniem, ale może spowodować niedopuszczalną ilość Pracuj teraz dla swoich programistów. Prawdopodobnie dlatego Twój poprzednik użył Task.Run(..).Wait().

+2

Pojęcie "async" rośnie [poprzez] twoją bazę kodu "brzmi podobnie do tego, co dzieje się, gdy ktoś wprowadza' IDisposable' gdzieś (podczas bocznego stawiania pytania o to, czy że użycie 'IDisposable' jest poprawne). –

+2

@Dan: Tak, są bardzo podobne problemy projektowe wspólne pomiędzy 'IDisposable' i' async'. –

4

Głównie tak.

Stosowanie tego typu jest używane głównie przez osoby, które nie wiedzą, jak wykonać metodę asynchroniczną.

Istnieje jednak różnica. Używanie Task.Run oznacza uruchamianie metody asynchronicznej na wątku ThreadPool.

Może to być przydatne, gdy synchroniczna część metody asynchronicznej (część przed pierwszym oczekiwaniem) jest znaczna, a osoba wywołująca chce się upewnić, że ta metoda nie jest blokowana.

Może to również służyć do "wydostania się" z bieżącego kontekstu, na przykład gdy nie ma SynchronizationContext.

+0

Tak, jakby uruchomienie 'Foo.StartAsync()' w wątku ThreadPool było ważne, można mieć nadzieję na komentarz do tego efektu? –

+1

@ Dan Nie powiedziałbym tego. Poza tym nie stanowi to problemu dla samej metody. Może to być problem dla dzwoniącego.Jeśli twój wątek jest "specjalny" (wątek UI lub oczekujesz na żądania) i chcesz odciążyć jak najwięcej innych wątków, możesz użyć 'Task.Run'. – i3arnon

+0

, więc zalecany sposób powinny być async czekać również w Task.Run? –

Powiązane problemy