public Task<Guid> GetMyObjectIdAsync(string objectName)
Gdy widzę to, spodziewam się tam, aby być pewną przewagę w raczej niż przy użyciu tej metody tylko owijając go w Task.Run()
siebie.
W szczególności spodziewam się, że uwalnia wątek, gdy trafi on w niektóre wejścia/wyjścia lub w inny sposób będzie mógł to zrobić.
teraz rozważyć, czy mam kod:
_resource = GetResourceForID(GetMyObjectIdAsync(SomeLongRunningWayToGetName()));
Jeśli mam powodu, by trzeba mieć to zrobić w zadaniu, a ja jestem w rodzaju sytuacji Task.Run()
ma właściwie sensu (mam powody, by odciążyć go na innym wątku), że najlepszym sposobem, aby to zrobić byłoby zawinąć całość:
Task task = Task.Run(() => _resource = GetResourceForID(GetMyObjectIdAsync(SomeLongRunningWayToGetName())));
Tutaj Task.Run()
może być zły pomysł dla mnie jak dzwoniący, lub może to być dobre, ponieważ naprawdę zyskuję na tym, co mi daje.
Jednak jeśli widzę twój podpis, zamierzam myśleć, że najlepszym sposobem, aby to zrobić z kodem byłoby, aby włączyć go do kodu, który używa tej metody.
Task task = SomeLongRunningWayToGetName()
.ContinueWith(t => GetMyObjectIdAsync(t.Result))
.ContinueWith(t => _resource = GetResourceForIDAsync(t.Result));
(lub podobnego używając async
i await
).
W najlepszym razie ma to mniejszą skuteczność w hakowaniu Task.Run()
. W gorszym jestem await
w to tylko po to, aby skorzystać z lepszej asynchroniczności, której nie oferuje w kontekście, który mógłby z niej skorzystać, gdyby rzeczywiście istniał. (E.g Mógłbym użyć tego w akcji MVC, którą zrobiłem asynchronicznie, ponieważ myślałem, że dodatkowy narzut zostanie spłacony w lepszym wykorzystaniu puli wątków).
Podczas gdy Task.Run()
jest czasami przydatna, w tym przypadku zawsze jest źle. Jeśli nie możesz zaoferować mi większej asynchroniczności, niż sam mogę wykorzystać w klasie, nie każ mi wierzyć, że to robisz.
Oferuję tylko publiczną metodę XXXAsync()
, jeśli rzeczywiście wywołuje ona asynchroniczne operacje we/wy.
Jeśli chcesz naprawdę potrzebujesz, aby wyłączyć metodę asynchroniczną, na przykład pasuje do podpisu ze wspólnej bazy lub interfejsu, to byłoby lepiej jak:
public Task<Guid> GetMyObjectIdAsync(string objectName)
{
return Task.FromResult(GetMyObjectId(objectName);
}
To jest złe zbyt (rozmówca nadal być lepiej po prostu dzwoniąc GetMyObjectId()
bezpośrednio), ale przynajmniej jeśli kod await
s wtedy, gdy działa na tym samym wątku, nie ma narzutu na użycie kolejnego wątku do wykonania pracy, więc jeśli jest zmieszany z innymi await
s, negatywny wpływ jest zredukowany. Dlatego warto, abynaprawdę musiał zwrócić Task
, ale nie można dodać coś przydatnego w tym, jak go nazwać.
Ale jeśli nie musisz naprawdę musisz zaoferować to,, po prostu nie rób tego.
(Prywatna metoda wywoływania Run()
, ponieważ każda strona z serwisem wywoławczym czerpie z niej korzyści, jest inna i nie tylko dodajesz wygodę, a nie wywołujesz Run()
w kilku miejscach, ale powinna ona być dobrze udokumentowana jako taka).
Dlaczego nie połączyć tych tajemniczych wpisów SO? Chodzi mi o to, że powinni już zawierać twoją odpowiedź, prawda? – nvoigt
Nie, w zasadzie, oni zawsze mówią: "Nie powinieneś używać Task.Run()" jako swego rodzaju wyrzucanego komentarza ... ale widziałem to wystarczająco, aby mnie martwić, że mogę zrobić to źle. –
https://channel9.msdn.com/Series/Three-Essential-Tips-for-Async/Async-Library-Methods-Shouldn-t-Lie – SLaks