Czy użycie async / wait tworzy nowy wątek?

Jestem nowy w TPL i zastanawiam się: jak wsparcie programowania asynchronicznego, które jest nowe w C# 5.0 (poprzez nowe słowa kluczowe async i await) ma się do tworzenia wątków?

W szczególności, czy użycie async/await tworzy nowy wątek za każdym razem, gdy są używane? A jeśli istnieje wiele zagnieżdżonych metod, które używają async/await, to czy dla każdej z tych metod tworzony jest nowy wątek?

Author: Community, 2014-12-03

5 answers

W skrócie NIE

From asynchroniczne Programowanie z Asynchronią i oczekują : Threads

Asynchroniczne i oczekujące słowa kluczowe nie powodują, że dodatkowe wątki będą stworzony. Metody asynchroniczne nie wymagają wielowątkowości, ponieważ asynchroniczne metoda nie działa na własnym wątku. Metoda działa na bieżącym kontekstu synchronizacji i używa czasu na wątku tylko wtedy, gdy metoda jest aktywna. Możesz użyć zadania.Uruchom, aby przenieść pracę związaną z procesorem do wątek tła, ale wątek w tle nie pomaga w procesie to tylko czekanie na wyniki, aby stać się dostępne.

 62
Author: Adriaan Stander,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-15 18:13:49

Według MSDN: asynchroniczne słowo kluczowe

Metoda asynchroniczna działa synchronicznie, dopóki nie osiągnie pierwszego wyrażenia oczekującego, w którym to momencie metoda jest zawieszona do zakończenia oczekiwanego zadania. W międzyczasie control powraca do wywołującego metodę, jak pokazuje przykład w następnej sekcji.

Oto przykładowy kod do sprawdzenia:

class Program

{
    static void Main(string[] args)
    {
        Program p = new Program();
        p.Run();
    }

    private void Print(string txt)
    {
        string dateStr = DateTime.Now.ToString("HH:mm:ss.fff");
        Console.WriteLine($"{dateStr} Thread #{Thread.CurrentThread.ManagedThreadId}\t{txt}");
    }

    private void Run()
    {
        Print("Program Start");
        Experiment().Wait();
        Print("Program End. Press any key to quit");
        Console.Read();
    }

    private async Task Experiment()
    {
        Print("Experiment code is synchronous before await");
        await Task.Delay(500);
        Print("Experiment code is asynchronous after first await");
    }
}

I wynik : Wynik eksperymentu: kod po uruchomieniu w innym wątku

Widzimy metodę code of Experiment () po oczekiwaniu wykonuje na innym wątku.

Ale jeśli zamienię zadanie.Delay by my own code (method SomethingElse):
   class Program
{
    static void Main(string[] args)
    {
        Program p = new Program();
        p.Run();
    }

    private void Print(string txt)
    {
        string dateStr = DateTime.Now.ToString("HH:mm:ss.fff");
        Console.WriteLine($"{dateStr} Thread #{Thread.CurrentThread.ManagedThreadId}\t{txt}");
    }

    private void Run()
    {
        Print("Program Start");
        Experiment().Wait();
        Print("Program End. Press any key to quit");
        Console.Read();
    }

    private async Task Experiment()
    {
        Print("Experiment code is synchronous before await");
        await SomethingElse();
        Print("Experiment code is asynchronous after first await");
    }

    private Task SomethingElse()
    {
        Print("Experiment code is asynchronous after first await");
        Thread.Sleep(500);
        return (Task.CompletedTask);
    }
}

Zauważyłem, że wątek pozostaje taki sam !

Wątek jest taki sam nawet z async / wait

Podsumowując, powiem, że kod async / wait może używać innego wątku, ale tylko jeśli wątek jest tworzony przez inny kod, a nie przez async / wait.

W tym przypadku myślę, że Task.Delay stworzył wątek, więc mogę stwierdzić, że async / wait nie tworzy nowego wątku jak powiedział @Adriaan Stander.

 6
Author: Elo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-14 12:40:41

Przepraszam za spóźnienie na imprezę.

Jestem nowy w TPL i zastanawiam się: jak asynchroniczne wsparcie programistyczne, które jest nowe w C# 5.0 (poprzez nowe asynchroniczne słowa kluczowe) dotyczą tworzenia wątków?

async/await nie jest wprowadzany do tworzenia wątków, ale do optymalnego wykorzystania bieżącego wątku.

Twoja aplikacja może odczytywać pliki, czekać na odpowiedź z innego serwera lub nawet wykonywać obliczenia z wysokim dostępem do pamięci (po prostu dowolne zadanie IO). Zadania te nie są obciążające procesor (każde zadanie, które nie będzie używać 100% wątku).

Pomyśl o tym, że przetwarzasz 1000zadań bez CPU . W tym przypadku proces tworzenia 1000 wątków na poziomie OS może pożreć więcej procesora i pamięci niż wykonywanie rzeczywistej pracy na pojedynczym wątku (4MB na wątek w Windows, 4MB * 1000 = 4GB). W tym samym czasie, jeśli uruchamiasz wszystkie zadania kolejno, być może będziesz musiał poczekać, aż zadania IO zostaną ukończone. Które kończą się w długim czas, aby zakończyć zadanie, utrzymując procesor bezczynny.

ponieważ wymagamy parralalizmu, aby szybko wykonać wiele zadań, jednocześnie wszystkie parellalne zadania nie są głodne procesora, ale tworzenie wątków jest nieefektywne.

Kompilator przerywa wykonanie przy każdym wywołaniu metody async (niezależnie od tego, czy jest ona awaited czy nie) i natychmiast wykonuje pozostały kod, po osiągnięciu await, wykonanie przejdzie do poprzedniego async. To będą powtarzane wielokrotnie, dopóki wszystkie wywołania asynchroniczne nie zostaną zakończone i ich awaiters nie zostaną spełnione.

Jeśli którakolwiek z metod asynchronicznych ma duże obciążenie CPU bez wywołania metody asynchronicznej, to tak, Twój system przestanie odpowiadać, a wszystkie pozostałe metody asynchroniczne nie zostaną wywołane, dopóki bieżące zadanie nie zostanie zakończone.

 4
Author: VibeeshanRC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-16 12:15:49

Czytałem więc o modelu threading i Async / wait z pewnością może prowadzić do użycia nowych wątków (niekoniecznie utworzonych - Pula tworzy je przy starcie aplikacji). To do schedulera należy ustalenie, czy potrzebny jest nowy wątek. I jak to widzę, wywołanie do oczekiwanej funkcji może mieć wewnętrzne szczegóły, które zwiększają szanse na scheduler wykorzystujący inny wątek; po prostu dlatego, że więcej pracy oznacza więcej możliwości / powodów dla scheduler do podzielenia się praca.

Operacje asynchroniczne WinRT są automatycznie wykonywane na puli wątków. I zazwyczaj będziesz wywoływać z puli wątków, z wyjątkiem pracy z wątkami UI .. Xaml / Input / Events.

Operacje asynchroniczne rozpoczęte na wątkach Xaml/UI mają swoje wyniki dostarczane z powrotem do wątku [wywołującego] UI. Ale wyniki operacji asynchronicznych rozpoczętych od wątku puli wątków są dostarczane wszędzie tam, gdzie następuje zakończenie, które może nie być tym samym wątkiem, w którym byłeś wcześniej. Powodem tego jest ten kod napisany dla puli wątków prawdopodobnie zostanie napisany jako bezpieczny dla wątków i jest również dla wydajności, Windows nie musi negocjować tego przełącznika wątków.

Więc ponownie, w odpowiedzi na OP, nowe wątki niekoniecznie są tworzone, ale Twoja aplikacja może i będzie używać wielu wątków do zakończenia pracy asynchronicznej.

Wiem, że wydaje się to sprzeczne z literaturą dotyczącą async / wait, ale to dlatego, że chociaż konstrukcja async / wait nie jest sama w sobie wielowątkowa. Jest to jeden z mechanizmów, za pomocą których scheduler może dzielić pracę i konstruować wywołania między wątki.

To jest na granicy mojej wiedzy w tej chwili na temat asynchronizacji i threadingu, więc może nie mam dokładnie tego dobrze, ale uważam, że ważne jest, aby zobaczyć związek między waitables i threading.

 1
Author: Gavin Williams,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-17 08:52:24

Użycie Async / wait niekoniecznie powoduje utworzenie nowego wątku. Ale użycie Async / wait może prowadzić do utworzenia nowego wątku, ponieważ funkcja awaitable może wewnętrznie wywołać nowy wątek. I często tak się dzieje, czyniąc stwierdzenie "Nie, Nie rodzi wątków" prawie bezużytecznym w praktyce. Na przykład poniższy kod powoduje powstanie nowych wątków.

VisualProcessor.Ctor()
{
    ...
    BuildAsync();
}

async void BuildAsync()
{
    ...
    TextureArray dudeTextures = await TextureArray.FromFilesAsync(…);
}

public static async Task<TextureArray> FromFilesAsync(...)
{    
    Debug.WriteLine("TextureArray.FromFilesAsync() T1 : Thread Id = " + GetCurrentThreadId());
    List<StorageFile> files = new List<StorageFile>();
    foreach (string path in paths)
    {
        if (path != null)
            files.Add(await Package.Current.InstalledLocation.GetFileAsync(path)); // << new threads
        else
            files.Add(null);
    }
    Debug.WriteLine("TextureArray.FromFilesAsync() T2 : Thread Id = " + GetCurrentThreadId());
    ...
}
 -3
Author: Gavin Williams,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-16 05:01:18