Problem ze zrozumieniem async

0

Cześć
Mam mały problem ze zrozumieniem pewnej rzeczy w poniższym kodzie:

 class Program
    {
        public static void Main(string[] args)
        {
            string url = "https://www.google.com/";
            Console.Write($"{url} \n");
            Task task = WriteWebRequestSizeAsync(url);

            for (int i = 0; i < 40; ++i)
            {
                for (int j = 0; j != 70000000; ++j)
                {
                }
                Console.WriteLine("wypisz tekst z metody main");
            }
            task.Wait();
            Console.ReadKey();
        }

        private static async Task WriteWebRequestSizeAsync(string url)
        {
            WebRequest webRequest = WebRequest.Create(url);
            WebResponse response = await webRequest.GetResponseAsync();

            using (StreamReader reader = new StreamReader(response.GetResponseStream()))
            {
                string text =
                await reader.ReadToEndAsync();
                Console.WriteLine(FormatBytes(text.Length));
            }
            for (int i = 0; i < 8; ++i)
            {
                for (int j = 0; j != 100000000; ++j)
                {
                }
                Console.WriteLine("metoda async");
            }
        }

Czy ktoś może mi wytłumaczyć czemu pętla wypisująca w konsoli słowo "metoda async" po wykonaniu wcześniejszego kodu z metody WriteWebRequestSizeAsync (która wypisuje po wczytaniu wielkość strony) jest wykonywana w innym wątku niż metoda main? Z tego co rozumiem async w metodzie nie oznacza utworzenia nowego wątku a sterowanie cały czas jest w wątku głównym, pozwala nam to tylko na użycie await. Więc dlaczego po wykonaniu przykładowego kodu przed pętlą, ona sama jest wykonywana równolegle razem z Console.WriteLine("wypisz tekst z metody main") a nie cała przed nią. Jeżeli pętlę dam na sam początek metody to nie będzie problemu i najpierw zostanie wypisane słowo "metoda async" 8 razy a potem reszta kodu równolegle z Console.Write("wpisz tekst z metody main"). Z tego co widzę to np. w kodzie źródłowym GetResponseAsync(), metoda ta zwraca "return Task.Run(() => ..." nie ważne, ale jak to ma się do mojej pętli że jest wykonywana w innym wątku niż main? Czemu po wykonani await coś tam nagle reszta metody działa równolegle z Console.WriteLine("wypisz tekst z metody main")?

Wiem, że to trochę pokręcone ale starałem się przekazać to najlepiej jak umiem na ten moment. W załączniku znajduje się screen z konsoli.

6

W skrócie bo jest już późno :P

Z brakiem wątku w async/await chodzi o to, że podczas wykonywania operacji asynchronicznej (dostęp do dysku, zapytanie sieciowe itp.) żaden wątek nie jest blokowany. Metoda wykonuje się na jakimś wątku. W końcu trafia na słówko await i wątek ten zostaje zwrócony do puli wątków dostępnych dla aplikacji (nie czeka blokująco na wykonanie się awaita, w międzyczasie może wykonywać inne zadania). Teraz w pewnym momencie metoda asynchroniczna na której użyte było await się kończy i dalsza jej część musi wykonać się na jakimś wątku.

A na jakim? To już zależy od kontekstu synchronizacji. Jeśli dobrze pamiętam apki konsolowe nie mają zaimplementowanego żadnego szczególnego kontekstu synchronizacji, więc kontynuacja zostanie wykonana na wątku z puli wątków (ThreadPool).

ASP.NET, WPF, WinForms mają swój kontekst synchronizacji, apki konsolowe, ASP.NET Core nie mają.

W WPF i WinForms jeśli wywołasz await w wątku UI to kontynuacja wykona się na tym samym wątku (UI). W przypadku ASP.NET przywrócony zostanie HttpContext.Current.

Związana z tym ciekawostka, jeśli w ASP.NET, WPF albo WinForms synchronicznie zblokujesz wywołanie asynchroniczne (np. (await MethodAsync().Result) to będziesz miał deadlocka, w przypadku apek konsolowych i ASP.NET Core deadlock nie nastąpi.

Poczytaj o SynchronizationContext i TaskScheduler.

//W sumie jak teraz patrzę to nie wiem czy ten mój wywód odpowiada na pytanie XD Bo chyba jednak w twoim przykładzie chodzi o coś trochę innego.

0

@some_ONE:
Dzięki za wyjaśnienie pewnych kwestii :)

some_ONE napisał(a):

//W sumie jak teraz patrzę to nie wiem czy ten mój wywód odpowiada na pytanie XD Bo chyba jednak w twoim przykładzie chodzi o coś trochę innego.

Twoja odpowiedź naprowadziła mnie raczej na to co mnie dręczyło:
https://stackoverflow.com/questions/37877803/use-of-async-await-in-console-or-web-apps

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