2016-04-15 30 views
10

Okay Mam nadzieję, że mam podstawy asynchroniczne/czekam, ale wciąż niektóre pytania pozostają w mojej głowie.Async/Await VS Task.Run: Kiedy używać? Jak używać?

Ale teraz to jest problem, o którym mówię. Załóżmy, że w tym prostym przykładzie

static void Main(string[] args) 
{ 

    Method(); 

    Console.WriteLine("Main Thread"); 

    Console.ReadLine(); 

} 

public async static void Method() 

{ 

    await Task.Run(new Action(LongTask)); 

    Console.WriteLine("New Thread"); 

} 

public static void LongTask() 

{ 

    Thread.Sleep(8000); 

    Console.WriteLine("Long Task"); 

} 

Główny gwint nadal trwa i drukuje Main Thread po wywołaniu metody() i czeka na napotkaniu przez 8 sekund.

Tak więc metoda() wraca do dzwoniącego, tj. Do głównej funkcji tutaj, gdy napotka oczekiwanie, zapisuje kontekst synchronizacji i kontynuuje wykonywanie z tego miejsca.

Drukuje najpierw Main Thread.

Następnie po upływie 8 sekund wydrukuj, Long Task, a następnie New Thread.

Ta część mam. Moje pytanie jest, w mojej aplikacji:

public IList<createcaseoutput> createCase(CreateCaseInput CreateCaseInput,SaveCaseSearchInput SaveCaseSearchInput)  
{ 
    ............. 
    SQL.CaseSQL.getCreateCaseParameters(CreateCaseInput, out strSPQuery, out listParam);  
    var AcctLst = rep.ExecuteStoredProcedure<createcaseoutput>(strSPQuery, listParam).ToList(); 

    if (!string.IsNullOrEmpty(AcctLst.ElementAt(0).o_case_seq.ToString())) 

    { 
     await saveCaseSearch(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq); 
    } 

    console.writeline("Async called"); 
    return AcctLst;  
} 

public async Task<ilist<savecasesearchoutput>> saveCaseSearch(SaveCaseSearchInput SaveCaseSearchInput,Int64? case_key) 

{ 
    .......................... 
    SQL.CaseSQL.getSaveCaseSearchParameters(SaveCaseSearchInput, case_key, out strSPQuery, out listParam); 

    var AcctLst = await rep.ExecuteStoredProcedureAsync<entities.case.savecasesearchoutput>(strSPQuery, listParam); 

    return AcctLst; 
} 

Tutaj również createCase napotyka czekają i powinien wrócić natychmiast w prawo i wykonać sam bardzo następnego wiersza i drukować Async called zanim nawet SaveCaseSearch uzupełnia prawo?

OK, jeśli myślę głośno, może to być control returns to the caller.

Więc jest to jak gdybym owinąć moje wezwanie SavCaseSearch wewnątrz innego async/czekają metoda nazwana przypuszczać

async DoWork() {.... 
} 

i nazywają to DoWork() z CreateCase() bezpośrednio więc wtedy

It will go on printing "Async called" once call to DoWork() encounters await and before it even completes ?

ja myślę w prawidłowy sposób?

czasami widzę i się mylić między

await someAsync() 

i

await Task.Run(() => someAsync()) ..

jaka jest różnica między nimi? i do którego należy podążać?

+1

Jeśli próbujesz użyć 'async' w aplikacji konsoli, możesz napotkać problemy, chyba że ustawisz je poprawnie, może nie zachowywać się zgodnie z oczekiwaniami w inny sposób. Zobacz http://anthonysteele.co.uk/async-and-await-with-console-apps i http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx –

+0

' async' to [nie dotyczy wątków] (http://stackoverflow.com/q/17661428/11683). – GSerg

+0

Zapoznaj się ze Stephen Cleary post o tym. Bardzo przydatne – Ian

Odpowiedz

4

Moje pytanie jest w mojej aplikacji:

Twój kod nie będzie kompilować, ponieważ używasz await bez async. Kod poprawione byłoby:

public async Task<IList<createcaseoutput>> createCaseAsync(CreateCaseInput CreateCaseInput,SaveCaseSearchInput SaveCaseSearchInput)  
{ 
    ... 
    await saveCaseSearch(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq); 
    console.writeline("Async called"); 
    return AcctLst;  
} 

Tutaj również createCase napotyka czekają i powinien wrócić natychmiast w prawo i wykonać bardzo następną linię samej nazwie i druk Async przed nawet SaveCaseSearch uzupełnia prawo?

nr Kod:

await saveCaseSearch(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq); 

jest taki sam jak ten kod:

var saveTask = saveCaseSearchAsync(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq); 
    await saveTask; 

Więc, po pierwsze, createCaseAsync nazwałbym saveCaseSearchAsync. Przypuszczalnie saveCaseSearchAsync wykonuje pewną operację asynchroniczną, więc zwróci niepełne zadanie do createCaseAsync. createCaseAsync, a następnie await to zadanie, które powoduje, że zwraca niepełne zadanie do swojego rozmówcy.

W końcu zakończy się zadanie saveCaseSearchAsync, które zakończy zadanie, które zostało zwrócone (które w powyższym kodzie nazwałem saveTask). To z kolei będzie kontynuować wykonywanie createCaseAsync, a następnie przejdzie do następnej linii i wydrukuje "Async wywołany" na konsoli.

Więc to jakbym owinąć moje wezwanie SavCaseSearch wewnątrz innego async/czekają metoda

Nie musiałby otoki ponieważ createCaseAsync już przekazujących Task.

jaka jest różnica między nimi? i do którego należy podążać?

Task.Run służy głównie do przepychania pracy blokującej z wątku UI i do wątku. Ponieważ jesteś na ASP.NET, nie używaj Task.Run.

1

Odnośnie różnicy między asynchroniczny/Zadania i czekają ...

asynchroniczny/Oczekujcie składniowe są słowa kluczowe w celu uproszczenia kodu, jak wszystko przed słowem kluczowym Oczekujcie dzieje się w wątku wywołującego i wszystko z Oczekiwanie na dalsze dzieje się w kontynuacji zadania.

Skonfigurowanie tego zadania przy użyciu licencji TPL będzie wymagać dużej ilości kodu i problemów z czytelnością. Zauważ jednak, że poniżej wciąż używa zadań i kontynuacji.

Ponadto, oni nie zawsze mogą być stosowane w miejsce czynności, jak przy zakończeniu Task jest niedeterministyczny, lub jeśli masz kilka poziomów zadań wraz z wykorzystaniem TaskCompletionSource.

Aby uzyskać więcej informacji przeczytaj rozdział 4 „Asynchronous Programming” w książce „Writing High-Performance .NET Code” Ben Watson

Uwaga również, Wewnętrznie OC korzysta z puli wątków .NET, ale robi to w bardziej inteligentny sposób, wykonując wiele zadań na tym samym wątku sekwencyjnie przed zwróceniem wątku z powrotem do puli. Może to zrobić poprzez inteligentne wykorzystanie obiektów delegowanych.

1

Tutaj również czeka na Ciebie createCase i powinien natychmiast powrócić do prawej strony i wykonać sam następny wiersz oraz wydrukować Async wywołane zanim nawet SaveCaseSearch zakończy się poprawnie?

To nie powinno nawet się kompilować. Operator "oczekujący" może być użyty tylko w metodzie "asynchronicznej". To powiedziawszy, jeśli usuniesz operator "oczekuj", to następny wiersz wyświetli "Asynchronizację nazwaną" zanim zakończy się saveCaseSearch.

Czy myślę w prawidłowy sposób?

saveCaseSearch jest już metodą "asynchroniczną", więc nie trzeba jej owijać, aby osiągnąć pożądany efekt. Powiedziałeś, że możesz go zawinąć w inną metodę, jeśli naprawdę chcesz.

jaka jest różnica między nimi? i do którego należy podążać?

Operator "oczekuj" czeka na obiekt zadania, więc jeden z nich jest w porządku. Wybrałem opcję await someAsync(), ponieważ jest to mniej kodu do napisania.

3

Pierwsza zasada asynchronizacji to zawsze asynchronizacja lub nigdy nie używaj asynchronizacji.

Jeśli twój bazowy interfejs API nie może obsłużyć asynchronizacji, nie ma sensu używać asynchronizacji w wyższych warstwach (np. ASP.NET MVC), ponieważ w pewnym momencie dostaniesz głód wątku, ponieważ wszystkie wątki są zajęte w oczekiwaniu na operacje IO (jak wywołania DB).

Twój przykład to klasyczny przypadek, w którym miksujesz synchronizację i asynchronizację. Wywołanie Sleep zablokuje wątek, dopóki się nie zakończy. Zamiast tego powinieneś użyć Task.Delay, ponieważ spowodowałoby to zwolnienie wątku do czasu zakończenia opóźnienia.

Moja rada jest taka, aby zacząć od przestrzegania reguły, o której wspomniałem wcześniej i tylko wtedy, gdy zaangażowane są operacje związane z IO, takie jak DB lub wywołania plików. Wtedy, gdy lepiej zrozumiesz asynchroniczne, możesz zacząć go łamać, ponieważ wtedy będziesz miał znacznie lepsze zrozumienie tego, do czego może to doprowadzić.

(Niestety, nie odpowiadamy bezpośrednio na twoje pytania, ale wątki są skomplikowanym tematem i twój mózg może się smażyć, jeśli spróbujesz wszystko bezpośrednio. Zacznij od małej.)