2015-03-03 10 views
10

Wezwę metodę asynchroniczną w mojej aplikacji konsoli. Nie chcę, aby aplikacja została zamknięta krótko po jej uruchomieniu, tj. Zanim zakończą się ważne zadania. Wydaje się, że mogę to zrobić:Dlaczego potrzebny jest AsyncContext podczas używania async/await z aplikacją konsolową?

internal static void Main(string[] args) 
{ 
    try 
    { 
     Task.WaitAll(DoThisAsync()); 
    } 
    catch (Exception ex) 
    { 
     Console.Error.WriteLine(ex); 
     throw; 
    } 
} 

internal static async Task DoThisAsync() 
{ 
    //... 
} 

Ale według Stephen Cleary's article wydaje się, że nie mogę tego zrobić i należy zamiast tworzyć jakiś kontekst dla asynchronicznych, aby powrócić do kiedy to zrobić (np AsyncContext).

Powyższy kod działa i zwraca się po głównym wątku po Task.WaitAll(DoThisAsync());, dlaczego więc muszę użyć niestandardowego kontekstu?

+0

Być może dzieje się tak, gdy używasz threadpool. Wątki Threadpool są wątkami tła, a główny wątek jest tylko pierwszym planem. Aplikacje interfejsu użytkownika będą miały pętlę główną, która nie pozwoli im wyjść, zanim coś się stanie, a aplikacje konsolowe zwykle nie mają tej pętli. Jeśli więc nie zablokujesz głównego wątku czekającego na coś, twoja aplikacja zostanie po prostu zakończona, a praca, którą wykonywałeś w wątku, zniknie. Nie jestem jednak pewien. – Spo1ler

+0

Jak wspomniano w @StephenCleary, jest to tylko preferencja. Nie ma znaczenia, w jaki sposób blokujesz wątek, po prostu musisz mieć świadomość, że jeśli nie będziesz w jakiś sposób zarządzać tym wątkiem, twoja aplikacja zostanie zamknięta (nawet jeśli twoje inne wątki nie zostaną wykonane) – Brandon

+0

@Bandon Cóż, to * ma znaczenie *. Działają inaczej, ale oczywiście można pisać programy robocze przy użyciu obu metod. – Servy

Odpowiedz

18

To nie jest wymagane; to tylko moje preferencje.

Można synchronicznie blokować zadanie w ramach Main (przy użyciu Wait/Result/WaitAll). Semantyka jest nieco inna; w szczególności, jeśli kod asynchroniczny ulegnie uszkodzeniu, wówczas Wait/Result/WaitAll zawinie wyjątek w AggregateException, podczas gdy AsyncContext nie.

Także, AsyncContext traktuje główną nić specjalnie; zamiast wysyłać kontynuacje do puli wątków, wyśle ​​je z powrotem do tego głównego wątku (domyślnie zawsze możesz użyć ConfigureAwait(false), aby tego uniknąć). Jest to przydatne, jeśli piszę aplikację konsolową "proof of concept", ponieważ AsyncContext zachowuje się bardzo podobnie do kontekstów interfejsu użytkownika.

Ale na koniec dnia, to tylko kwestia preferencji.

+0

Będę musiał pamiętać, że głównym celem AsyncContext jest symulacja interfejsu użytkownika. –

+0

Dlaczego [AsyncContext] (https://github.com/StephenCleary/AsyncEx/tree/master/Source/Nito.AsyncEx%20 (NET45% 2C% 20Win8% 2C% 20WP8% 2C% 20WPA81)) wymaga tak dużej ilości kodu czy wszystko, co robisz, uniemożliwia 'AggregateException'? Widzę TaskScheduler, TaskQueue (BlockingQueue), TaskFactory i AsyncContextSynchronizationContext. Widzę AsyncContextThread, który mówi, że wykonuje działania dla AsyncContext. Sądzę, że moim zdaniem wiele się tu dzieje, ale nie znalazłem dobrego zapisu na temat tego, co się naprawdę dzieje. Nie mam czasu, aby spróbować rozszyfrować to, co się dzieje. – crush

+0

Czy masz gdzieś blog, który wyjaśnia, co dzieje się pod maską? Wszystko, co widzę, to to, że '.Result' i' .Wait() 'są złe i zamiast tego powinienem użyć twojego' AsyncContext'. Czemu? Co robi "AsyncContext" inaczej, co czyni go lepszym wyborem? Wydaje mi się, że planujesz zadania uruchamiane w wątku w tle, więc jeśli główny wątek zostanie zamknięty, będą one kontynuowane do ukończenia? Czy to jest poprawne? – crush