async await a wątki

0

Czy async/await tworzy nowy wątek do Taska a w starym przekauzje sterowanie do metody wywołujacej?

0

https://msdn.microsoft.com/en-us/library/hh191443.aspx

The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread.

0

Trochę enigmatyczne to tłumaczenie w dokumentacji. "Doesn't run on its own thread" - jak to rozumieć? Autorowi chodziło o to, że dla każdego zadania nie jest tworzony nowy osobny wątek, który byłby wyłączną własnością zadania? Czy że zadanie wykonuje się dokładnie w tym samym wątku, który wywołał metodę async? Ale jakby się wykonywał w tym samym wątku, to byłoby to trochę bez sensu (za wyjątkiem sytuacji, gdy programista tego jawnie żąda), bo nie dałoby się uzyskać równoległości na CPU - mielibyśmy trochę takiego GILa jak w Pythonie.

Dlatego domyślam się, że jest to zrobione tak samo jak w Javie/Scali tj. zadanie asynchroniczne jest wrzucane do jakiejś globalnej kolejki i wykonywane przez jeden z (prawdopodobnie wielu) wątków obsługujących tę kolejkę. Natomiast kod async/await jest przekształcany w maszynę stanów, która może generować nowe zadania, w chwili gdy poprzednie się zakończą, a kod zależny od rezultatu await jest przekształcany w kontunuację będącą częścią zadania wrzucanego przez inne async wywołane pod await. W ten sposób nigdy nie trzeba nic blokować i zawieszać wątku - jak dochodzi do await(), to system kończy bieżące zadanie i bierze po prostu kolejne zadanie z kolejki.

3

Samo pojawienie się w kodzie Task nie mówi kompletnie nic o tym w jaki sposób zostanie on wykonany. Task to zwykła abstrakcja, obietnica, promesa, że otrzymamy w przyszłości wynik. To co się właściwie dzieje jest niezależne i sam Task może o tym nawet nie wiedzieć. A rodzajów "tego co się dzieje" jest kilka.
Pierwszy to klasyczny przypadek operacji CPU-bound, czyli np. stworzenie Task poprzez Task.StartNew(), który spowoduje wykonanie przekazanej delegaty w ThreadPoolu, co może faktycznie oznaczać stworzenie nowego wątku (AFAIR według algorytmu Hill Climbing).
Kolejny to "opakowanie" pary Begin* oraz End*, które z kolei najczęściej w Windows reprezentują operację asynchroniczną overlapped z wykorzystaniem IOCP. Tutaj w skrócie mówiąc "promesa" występuje na poziomie systemu operacyjnego i sterownika urządzenia, które to o wykonanej operacji informuje za pomocą przerwania i system wywołuje odpowiedni callback na threadpoolu IOCP (który w .NET powiadomi Task o wykonanym zadaniu). Wchodzą w to właściwie wszystkie operacje na plikach, strumieniach (w tym sieciowych), czyli np. wszystko to stanie się pod spodem Task zwróconego przez FileStream.ReadAsync(). Nie jest tutaj tworzony żaden nowy wątek, nie jest używany żaden threadpool (prócz tego IOCP, ale te wątki są dzielone na wszystkie operacje IO i nie jest ich nigdy więcej niż 2 x ilość core'ów) i co najważniejsze - żaden wątek nie jest blokowany i nie czeka na wykonanie operacji IO.
Oczywiście możemy sobie podpiąć pod Task własny rodzaj pracy np. za pomocą TaskCompletionSource i użyć w nim innego z asynchronicznych prymitywów systemu albo co tam sobie wymyślimy.

A samo async/await zamienia naszą funkcję w maszynę stanów i wszystko co znajduje się pomiędzy await umieszcza tak jakby w kontynuacjach do zwracanego tasku. W przypadku awaitowania Tasków to SynchronizationContext decyduje o tym w jaki sposób się te kontynuacje wykonają i tak w przypadku Windows Forms to, co po await zawsze będzie wykonane na wątku UI, a w ASP.NET w wątku obsługującym request.

czyli jak zrobię { Task<int> a = doAsync1(); Task<int> b = doAsync2(); return (await a) + (await b) } to się wykonają sekwencyjnie, a nie rówlolegle.

Same Taski i async/await nie zapewniają równoległości. Zależy to wszystko od tego jaka praca kryje się za taskami zwróconymi przez doAsync1/2();. Praca nie zaczyna się w momencie wykonania await. Ale gdyby miało się to wykonywać sekwencyjnie to nie miałoby za bardzo sensu korzystanie i z asynchroniczności.

1 użytkowników online, w tym zalogowanych: 0, gości: 1