Jak i kiedy używać 'async' i 'wait'

Z mojego zrozumienia jedna z głównych rzeczy, które async oraz await czy aby Kod był łatwy do zapisu i odczytu - ale czy używanie ich jest równe zrolowaniu wątków tła do wykonywania długotrwałej logiki?

Obecnie wypróbowuję najbardziej podstawowy przykład. Dodałem kilka komentarzy. Możesz mi to wyjaśnić?

// I don't understand why this method must be marked as `async`.
private async void button1_Click(object sender, EventArgs e)
{
    Task<int> access = DoSomethingAsync();
    // task independent stuff here

    // this line is reached after the 5 seconds sleep from 
    // DoSomethingAsync() method. Shouldn't it be reached immediately? 
    int a = 1; 

    // from my understanding the waiting should be done here.
    int x = await access; 
}

async Task<int> DoSomethingAsync()
{
    // is this executed on a background thread?
    System.Threading.Thread.Sleep(5000);
    return 1;
}
Author: Roy, 2013-01-22

20 answers

Podczas używania async i await kompilator generuje maszynę stanową w tle.

Oto przykład, na którym mam nadzieję mogę wyjaśnić niektóre szczegóły wysokiego szczebla, które się dzieją:

public async Task MyMethodAsync()
{
    Task<int> longRunningTask = LongRunningOperationAsync();
    // independent work which doesn't need the result of LongRunningOperationAsync can be done here

    //and now we call await on the task 
    int result = await longRunningTask;
    //use the result 
    Console.WriteLine(result);
}

public async Task<int> LongRunningOperationAsync() // assume we return an int from this long running operation 
{
    await Task.Delay(1000); // 1 second delay
    return 1;
}

OK, więc co tu się dzieje:

  1. Task<int> longRunningTask = LongRunningOperationAsync(); rozpoczyna wykonywanie LongRunningOperation

  2. Niezależna praca jest wykonywana na Załóżmy główny wątek (Thread ID = 1) wtedy await longRunningTask jest osiągnięta.

    Teraz, Jeśli longRunningTask nie skończył i nadal jest po uruchomieniu, MyMethodAsync() powróci do swojej metody wywołania, więc główny wątek nie zostanie zablokowany. Po wykonaniu longRunningTask wątek z ThreadPool (może być dowolnym wątkiem) powróci do MyMethodAsync() w swoim poprzednim kontekście i kontynuuje wykonywanie (w tym przypadku drukowanie wyniku na konsoli).

Drugim przypadkiem byłoby to, że longRunningTask zakończył już swoje wykonanie i wynik jest dostępny. Po osiągnięciu await longRunningTask mamy już wynik, więc kod będzie kontynuowany wykonanie na tym samym wątku. (w tym przypadku drukowanie wyniku do konsoli). Oczywiście nie jest tak w przypadku powyższego przykładu, w którym występuje Task.Delay(1000).

 573
Author: Dan Dinu,
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
2017-10-11 23:43:35

Dalej do innych odpowiedzi, spójrz na wait (C# Reference)

A dokładniej na załączonym przykładzie nieco wyjaśnia twoją sytuację

Poniższy przykład Windows Forms ilustruje użycie metoda async, WaitAsynchronouslyAsync. Kontrastować z zachowaniem tego metoda z zachowaniem Waitsynchronicznie. Bez czekania operator zastosowany do zadania, Waitsynchronicznie działa synchronicznie pomimo stosowania async modyfikator w swojej definicji i wywołanie do Nić.Śpij w jego ciele.

private async void button1_Click(object sender, EventArgs e)
{
    // Call the method that runs asynchronously.
    string result = await WaitAsynchronouslyAsync();

    // Call the method that runs synchronously.
    //string result = await WaitSynchronously ();

    // Display the result.
    textBox1.Text += result;
}

// The following method runs asynchronously. The UI thread is not
// blocked during the delay. You can move or resize the Form1 window 
// while Task.Delay is running.
public async Task<string> WaitAsynchronouslyAsync()
{
    await Task.Delay(10000);
    return "Finished";
}

// The following method runs synchronously, despite the use of async.
// You cannot move or resize the Form1 window while Thread.Sleep
// is running because the UI thread is blocked.
public async Task<string> WaitSynchronously()
{
    // Add a using directive for System.Threading.
    Thread.Sleep(10000);
    return "Finished";
}
 133
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
2017-05-23 09:31:58

Z mojego zrozumienia jedną z głównych rzeczy, które robią asynchroniczne i oczekujące, jest ułatwienie pisania i czytania kodu.

Mają sprawić, że asynchroniczny kod będzie łatwy do zapisu i odczytu, tak.

Czy to to samo, co spawanie wątków tła do wykonywania długotrwałej logiki?

Wcale nie.

/ / nie rozumiem dlaczego ta metoda musi być oznaczona jako "async".

Słowo kluczowe async włącza await słowo kluczowe. Tak więc każda metoda wykorzystująca await musi być oznaczona async.

/ / ten wiersz jest osiągany po 5 sekundowym uśpieniu z metody DoSomethingAsync (). Nie powinien być natychmiast osiągnięty?

Nie, ponieważ async metody nie są domyślnie uruchamiane w innym wątku.

/ / czy jest to wykonywane na wątku tła?

Nie.

You may find my async/await intro pomocne. oficjalne dokumenty MSDN są również niezwykle dobre (szczególnie sekcja TAP), a zespół async wystawił doskonały FAQ .

 110
Author: Stephen Cleary,
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
2014-06-13 12:49:02

Wyjaśnienie

Poniżej znajduje się krótki przykład async / wait na wysokim poziomie. Istnieje wiele więcej szczegółów do rozważenia poza tym.

Uwaga: Task.Delay(1000) symuluje wykonywanie pracy przez 1 sekundę. Myślę, że najlepiej jest myśleć o tym jako o czekaniu na odpowiedź z zewnętrznego zasobu. Ponieważ nasz kod czeka na odpowiedź, system może ustawić uruchomione zadanie na boku i wrócić do niego po jego zakończeniu. Tymczasem może wykonać inne prace nad tym wątkiem.

W przykład poniżej, pierwszy blok robi dokładnie to. Uruchamia wszystkie zadania natychmiast (linie Task.Delay) i ustawia je na bok. Kod zatrzyma się na linii await a do czasu zakończenia 1-sekundowego opóźnienia przed przejściem do następnej linii. Od b, c, d, i e wszystkie rozpoczęły wykonywanie niemal dokładnie w tym samym czasie co a (z powodu braku oczekiwania), powinny zakończyć się mniej więcej w tym samym czasie w tym przypadku.

W poniższym przykładzie druga blok {[25] } rozpoczyna zadanie i czeka na jego zakończenie (tak robi await) przed rozpoczęciem kolejnych zadań. Każda iteracja tego zajmuje 1 sekundę. await wstrzymuje program i czeka na wynik przed kontynuacją. Jest to główna różnica między pierwszym i drugim blokiem.

Przykład

Console.WriteLine(DateTime.Now);

// This block takes 1 second to run because all
// 5 tasks are running simultaneously
{
    var a = Task.Delay(1000);
    var b = Task.Delay(1000);
    var c = Task.Delay(1000);
    var d = Task.Delay(1000);
    var e = Task.Delay(1000);

    await a;
    await b;
    await c;
    await d;
    await e;
}

Console.WriteLine(DateTime.Now);

// This block takes 5 seconds to run because each "await"
// pauses the program until the task finishes
{
    await Task.Delay(1000);
    await Task.Delay(1000);
    await Task.Delay(1000);
    await Task.Delay(1000);
    await Task.Delay(1000);
}
Console.WriteLine(DateTime.Now);

Wyjście:

5/24/2017 2:22:50 PM
5/24/2017 2:22:51 PM (First block took 1 second)
5/24/2017 2:22:56 PM (Second block took 5 seconds)

Dodatkowe informacje dotyczące SynchronizationContext

Uwaga: tutaj sprawy stają się dla mnie trochę mgliste, więc jeśli się mylę, popraw mnie, a ja zaktualizuję odpowiedź. Ważne jest, aby mieć podstawową wiedzę o tym, jak to działa, ale możesz przetrwać bez bycia ekspertem, o ile nigdy nie używasz ConfigureAwait(false), chociaż prawdopodobnie stracisz szansę na optymalizację, zakładam.

Jest jeden aspekt, który sprawia, że asynchroniczne/oczekujące pojęcie nieco trudniejsze do uchwycenia. To fakt, że w tym przykładzie wszystko dzieje się w tym samym wątku (a przynajmniej co wydaje się być tym samym wątkiem, jeśli chodzi o jego Synchronizacjękontekst). Domyślnie await przywróci kontekst synchronizacji oryginalnego wątku, na którym był uruchomiony. Na przykład w ASP.NET masz HttpContext, który jest powiązany z wątkiem, gdy pojawia się żądanie. Ten kontekst zawiera rzeczy specyficzne dla oryginalnego żądania Http, takie jak oryginalny obiekt żądania, który ma takie rzeczy jak język, adres IP, nagłówki itp. Jeśli zmienisz wątki w połowie przetwarzania coś, potencjalnie możesz próbować wyciągnąć informacje z tego obiektu na innym HttpContext, co może być katastrofalne. Jeśli wiesz, że nie będziesz używać kontekstu do niczego, możesz wybrać "nie dbać" o to. Zasadniczo pozwala to na uruchamianie kodu w osobnym wątku bez wprowadzania kontekstu. Jak to osiągnąć? Domyślnie kod await a; zakłada, że chcesz przechwycić i przywrócić kontekst:
await a; //Same as the line below
await a.ConfigureAwait(true);

Jeśli chcesz zezwolić na kontynuowanie głównego kodu w nowym wątku bez oryginalnego kontekstu, po prostu użyj false zamiast true, aby wiedział, że nie trzeba przywracać kontekstu.

await a.ConfigureAwait(false);

Po zatrzymaniu programu, będzie on kontynuowany potencjalnie w zupełnie innym wątku z innym kontekstem. Stąd pochodzi poprawa wydajności-może być kontynuowana w dowolnym dostępnym wątku bez konieczności Przywróć pierwotny kontekst, od którego się zaczęło.

Czy to jest mylące? O tak! Możesz to rozgryźć? Prawdopodobnie! Gdy już opanujesz pojęcia, przejdź do wyjaśnień Stephena Cleary ' ego, które zazwyczaj są nastawione bardziej na kogoś z technicznym zrozumieniem asynchronicznego/oczekującego.
 95
Author: Joe Phillips,
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-05-08 14:58:30

Pokazanie powyższych wyjaśnień w działaniu w prostym programie konsolowym -

class Program
{
    static void Main(string[] args)
    {
        TestAsyncAwaitMethods();
        Console.WriteLine("Press any key to exit...");
        Console.ReadLine();
    }

    public async static void TestAsyncAwaitMethods()
    {
        await LongRunningMethod();
    }

    public static async Task<int> LongRunningMethod()
    {
        Console.WriteLine("Starting Long Running method...");
        await Task.Delay(5000);
        Console.WriteLine("End Long Running method...");
        return 1;
    }
}

A Wyjście To:

Starting Long Running method...
Press any key to exit...
End Long Running method...

Tak więc,

  1. Main uruchamia metodę long running poprzez TestAsyncAwaitMethods. To natychmiast powraca bez zatrzymywania bieżącego wątku i natychmiast widzimy komunikat' Press any key to exit '
  2. / Align = "left" / Po jego zakończeniu inny wątek z Threadpool pobiera ten kontekst i wyświetla ostatnia wiadomość

W ten sposób nie wątek jest blokowany.

 45
Author: sppc42,
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
2015-08-13 09:32:13

Myślę, że wybrałeś zły przykład z System.Threading.Thread.Sleep

Punkt async zadania polega na tym, aby pozwolić mu wykonywać go w tle bez blokowania głównego wątku, np. wykonując DownloadFileAsync

System.Threading.Thread.Sleep nie jest czymś ,co jest "robione", to po prostu śpi, a zatem następna linia jest osiągana po 5 sekundach ...

Przeczytaj ten artykuł, myślę, że jest to świetne Wyjaśnienie async i await koncepcji: http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx

 35
Author: Vnuk,
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
2016-01-29 07:40:48

Oto szybki program konsoli, aby wyjaśnić tym, którzy podążają. Metoda "Taskodo" jest twoją długotrwałą metodą, którą chcesz asynchronizować. Uruchamianie asynchroniczne odbywa się metodą TestAsync. Metoda pętli testowych po prostu uruchamia zadania "Taskodo" i uruchamia je asynchronicznie. Widać to w wynikach, ponieważ nie kończą się one w tej samej kolejności od uruchomienia do uruchomienia - po zakończeniu zgłaszają się do wątku interfejsu konsoli. Uproszczone, ale myślę, że uproszczone przykłady wydobyć rdzeń wzorca lepiej niż bardziej zaangażowane przykłady:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TestingAsync
{
    class Program
    {
        static void Main(string[] args)
        {
            TestLoops();
            Console.Read();
        }

        private static async void TestLoops()
        {
            for (int i = 0; i < 100; i++)
            {
                await TestAsync(i);
            }
        }

        private static Task TestAsync(int i)
        {
            return Task.Run(() => TaskToDo(i));
        }

        private async static void TaskToDo(int i)
        {
            await Task.Delay(10);
            Console.WriteLine(i);
        }
    }
}
 17
Author: MarkWalls,
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
2015-09-11 09:23:45

Ta odpowiedź ma na celu dostarczenie pewnych informacji specyficznych dla ASP.NET.

Wykorzystując asynchroniczne / oczekujące w kontrolerze MVC, możliwe jest zwiększenie wykorzystania puli wątków i osiągnięcie znacznie lepszej przepustowości, jak wyjaśniono w poniższym artykule,

Http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4

W aplikacjach internetowych, które widzą dużą liczbę jednoczesnych żądań w rozruchu lub ma bursty load (gdzie współbieżność wzrasta nagle), asynchroniczne wywołanie tych usług internetowych zwiększy czas reakcji aplikacji. Żądanie asynchroniczne przyjmuje taki sam czas do przetworzenia jak żądanie synchroniczne. Na przykład, jeśli żądanie wykona połączenie z serwisem internetowym, które wymaga dwóch sekund na ukończone, żądanie trwa dwie sekundy, niezależnie od tego, czy zostanie wykonane synchronicznie lub asynchronicznie. Jednak podczas połączenia asynchronicznego, wątek nie jest blokowany w odpowiedzi na inne żądania podczas czeka na pierwszą prośbę do wypełnienia. Dlatego asynchroniczne żądania uniemożliwiają kolejkowanie żądań i wzrost puli wątków, gdy są wiele jednoczesnych żądań, które wywołują długotrwałe operacje.

 10
Author: Lex Li,
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
2014-09-08 02:06:42

Szczerze mówiąc nadal uważam, że najlepszym wyjaśnieniem jest to o przyszłości i obietnicach na Wikipedii: http://en.wikipedia.org/wiki/Futures_and_promises

Podstawową ideą jest to, że masz oddzielną pulę wątków, które wykonują zadania asynchronicznie. Podczas korzystania z niego. Obiekt składa jednak obietnicę, że w pewnym momencie wykona operację i poda wynik, gdy ją zażądasz. Oznacza to, że zablokuje się, gdy zażądasz wyniku i nie zakończone, ale wykonaj w puli wątków inaczej.

Stamtąd możesz zoptymalizować rzeczy: niektóre operacje mogą być zaimplementowane asynchronicznie i możesz zoptymalizować rzeczy, takie jak IO plików i komunikacji sieciowej, grupując kolejne żądania i / lub zmieniając ich kolejność. Nie jestem pewien, czy jest to już w ramach zadań Microsoftu - ale jeśli nie jest to jedna z pierwszych rzeczy, które dodałbym.

W C # 4.0 można zaimplementować przyszłościowy wzór. Jeśli chcesz wiedzieć, jak to dokładnie działa, mogę polecić ten link, który robi przyzwoitą robotę: http://code.google.com/p/fracture/source/browse/trunk/Squared/TaskLib /. Jeśli jednak zaczniesz się nim bawić, zauważysz, że naprawdę potrzebujesz wsparcia językowego, jeśli chcesz robić wszystkie fajne rzeczy-co dokładnie zrobił Microsoft.

 9
Author: atlaste,
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
2013-01-22 10:16:25

Wszystkie odpowiedzi tutaj używają zadania.Delay() lub innej wbudowanej funkcji asynchronicznej. Ale oto mój przykład, który nie używa żadnej z tych funkcji asynchronicznych:

    // Starts counting to a large numbewr and then immediately displays message "i'm counting...". 
    // Then it waits for task to finish and displays "finished, press any key".
    static void asyncTest ()
    {
        Console.WriteLine("Started asyncTest()");
        Task<long> task = asyncTest_count();
        Console.WriteLine("Started counting, please wait...");
        task.Wait(); // if you comment this line you will see that message "Finished counting" will be displayed before we actually finished counting.
        //Console.WriteLine("Finished counting to " + task.Result.ToString()); // using task.Result seems to also call task.Wait().
        Console.WriteLine("Finished counting.");
        Console.WriteLine("Press any key to exit program.");
        Console.ReadLine();
    }

    static async Task<long> asyncTest_count()
    {
        long k = 0;
        Console.WriteLine("Started asyncTest_count()");
        await Task.Run(() =>
        {
            long countTo = 100000000;
            int prevPercentDone = -1;
            for (long i = 0; i <= countTo; i++)
            {
                int percentDone = (int)(100 * (i / (double)countTo));
                if (percentDone != prevPercentDone)
                {
                    prevPercentDone = percentDone;
                    Console.Write(percentDone.ToString() + "% ");
                }

                k = i;
            }
        });
        Console.WriteLine("");
        Console.WriteLine("Finished asyncTest_count()");
        return k;
    }
 8
Author: Tone Škoda,
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
2017-07-15 08:03:51

Zobacz to skrzypce https://dotnetfiddle.net/VhZdLU (i poprawić go, jeśli to możliwe) do uruchomienia prosta aplikacja konsolowa który pokazuje zastosowania Task, Task.Operatory WaitAll (), async i wait w tym samym programie.

To skrzypce powinny oczyścić twoją koncepcję cyklu realizacji.

Oto przykładowy kod

using System;
using System.Threading.Tasks;

public class Program
{
    public static void Main()
    {               
        var a = MyMethodAsync(); //Task started for Execution and immediately goes to Line 19 of the code. Cursor will come back as soon as await operator is met       
        Console.WriteLine("Cursor Moved to Next Line Without Waiting for MyMethodAsync() completion");
        Console.WriteLine("Now Waiting for Task to be Finished");       
        Task.WaitAll(a); //Now Waiting      
        Console.WriteLine("Exiting CommandLine");       
    }

    public static async Task MyMethodAsync()
    {
        Task<int> longRunningTask = LongRunningOperation();
        // independent work which doesn't need the result of LongRunningOperationAsync can be done here
        Console.WriteLine("Independent Works of now executes in MyMethodAsync()");
        //and now we call await on the task 
        int result = await longRunningTask;
        //use the result 
        Console.WriteLine("Result of LongRunningOperation() is " + result);
    }

    public static async Task<int> LongRunningOperation() // assume we return an int from this long running operation 
    {
        Console.WriteLine("LongRunningOperation() Started");
        await Task.Delay(2000); // 2 second delay
        Console.WriteLine("LongRunningOperation() Finished after 2 Seconds");
        return 1;
    }   

}

ślad wychodzący z okna wyjścia: Tutaj wpisz opis obrazka

 6
Author: vibs2006,
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-01-24 12:45:39
public static void Main(string[] args)
{
    string result = DownloadContentAsync().Result;
    Console.ReadKey();
}

// You use the async keyword to mark a method for asynchronous operations.
// The "async" modifier simply starts synchronously the current thread. 
// What it does is enable the method to be split into multiple pieces.
// The boundaries of these pieces are marked with the await keyword.
public static async Task<string> DownloadContentAsync()// By convention, the method name ends with "Async
{
    using (HttpClient client = new HttpClient())
    {
        // When you use the await keyword, the compiler generates the code that checks if the asynchronous operation is finished.
        // If it is already finished, the method continues to run synchronously.
        // If not completed, the state machine will connect a continuation method that must be executed WHEN the Task is completed.


        // Http request example. 
        // (In this example I can set the milliseconds after "sleep=")
        String result = await client.GetStringAsync("http://httpstat.us/200?sleep=1000");

        Console.WriteLine(result);

        // After completing the result response, the state machine will continue to synchronously execute the other processes.


        return result;
    }
}
 3
Author: Weslley Rufino de Lima,
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-02-22 15:49:47

Z tego co rozumiem, to również powinno być dodane trzecie określenie: Task.

Async to tylko kwalifikator, który umieścisz w swojej metodzie, aby powiedzieć, że jest to metoda asynchroniczna.

Task jest zwrotem funkcji async. Wykonuje asynchronicznie.

Ty await zadanie. Gdy wykonanie kodu osiągnie tę linię, sterowanie wyskakuje z powrotem do wywołującego otaczającą cię oryginalną funkcję.

Jeśli zamiast tego przypisujesz zwracaną funkcję async (ie Task) do zmienna, gdy wykonanie kodu dotrze do tej linii, po prostu kontynuuje obok tej linii w otaczającej funkcji , podczas gdy Task wykonuje asynchronicznie.

 2
Author: user21306,
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
2017-06-02 21:15:25

Dla najszybszej nauki..

  • Zrozumieć przebieg wykonania metody( ze schematem): 3 mins

  • Pytanie introspekcja( nauka): 1 min

  • Szybko przejść przez cukier składniowy: 5 min

  • Podziel się zamieszaniem dewelopera: 5 minut

  • Problem: szybko zmienić rzeczywistą implementację normalnego kodu na Kod Async: 2 mins

  • Gdzie Następny?

Zrozumieć przepływ wykonania metody( ze schematem): 3 mins

Na tym obrazku skup się na # 6 Tutaj wpisz opis obrazka

W kroku # 6: AccessTheWebAsync () skończyła się praca, którą może wykonać bez wyniku getStringTask. W związku z tym AccessTheWebAsync używa operatora oczekującego, aby zawiesić jego postęp i oddać kontrolę (yield) wywołującemu. AccessTheWebAsync zwraca zadanie (o wartości zwracanej łańcuchem znaków) do wywołującego. Zadanie stanowi obietnica wytworzenia wyniku ciąg. Ale kiedy oddzwoni? znowu drugi telefon?

Wywołanie AccessTheWebAsync() nie robiło nic poza czekaniem (mogło wykonać pewne wewnętrzne zadania, a następnie czekać w razie potrzeby). Więc dzwoniący czeka na AccessTheWebAsync, a AccessTheWebAsync czeka na GetStringAsync w tej chwili.

Pamiętaj, że metoda została już zwrócona, nie może powrócić ponownie(nie po raz drugi). Skąd rozmówca się dowie? It is all about zadania! zadanie zostało zwrócone. zadanie czekało na (Nie metoda, nie wartość). Wartość zostanie ustawiona w zadaniu. Status zadania zostanie ustawiony na ukończenie. Rozmówca monitoruje zadanie. Dalsze czytanie na później tutaj .

Pytanie introspekcja do nauki: 1 min

Dostosujmy nieco pytanie:

Jak i kiedy stosować async oraz await Tasks?

Ponieważ nauka Task automatycznie obejmuje pozostałe 2. Przynajmniej dla nauki. Oczywiście jest to odpowiedź na twoje pytanie dotyczące async i await.

Szybko przejść przez cukier składniowy: 5 min

  • Przed konwersją

    internal static int Method(int arg0, int arg1) { int result = arg0 + arg1; IO(); // Do some long running IO. return result; }

  • Kolejne zadanie-jeśli metoda wywoła powyższą metodę

    internal static Task<int> MethodTask(int arg0, int arg1) { Task<int> task = new Task<int>(() => Method(arg0, arg1)); task.Start(); // Hot task (started task) should always be returned. return task; }

Wspomnieliśmy wait czy async? Nie. Zadzwoń do powyższej metody i otrzymasz zadanie. Które możesz monitorować. Już wiesz, co to za zadanie zwroty.. liczba całkowita.

  • Wywołanie zadania jest nieco trudne. Wywołajmy MethodTask ()

    internal static async Task<int> MethodAsync(int arg0, int arg1) { int result = await HelperMethods.MethodTask(arg0, arg1); return result; }

Czekamy na zakończenie zadania. Stąd await. Ponieważ używamy wait, musimy używać async (obowiązkowe) i MethodAsync z' Async ' jako prefiksem (standard kodowania). Więcej informacji na później tutaj

Podziel się zamieszaniem dewelopera: 5 min

Programista popełnił błąd nie implementując Ale to nadal działa! Spróbuj zrozumieć pytanie i tylko zaakceptowaną odpowiedź podaną tutaj . Mam nadzieję, że przeczytałeś i w pełni zrozumiałeś. Podobnie w naszym przykładzie wywołanie już zbudowanej MethodAsync() jest o wiele łatwiejsze niż zaimplementowanie tej metody z Task (MethodTask()) nas samych. Większość programistów ma trudności z opanowaniem Tasks podczas konwersji kodu na asynchroniczny.

Wskazówka: spróbuj znaleźć istniejącą implementację asynchroniczną (jak MethodAsync lub ToListAsync) do outsourcingu trudność. Tak więc musimy tylko poradzić sobie z Asynchronią i czekać (co jest łatwe i dość podobne do normalnego kodu)

Problem: szybko zmienić rzeczywistą implementację normalnego kodu na Działanie asynchroniczne: 2 min

Linia kodu pokazana poniżej w warstwie danych zaczęła pękać (w wielu miejscach). Ponieważ zaktualizowaliśmy część naszego kodu z. Net framework 4.2 do. Net core. Musieliśmy to naprawić w ciągu godziny w całej aplikacji!

var myContract = query.Where(c => c.ContractID == _contractID).First();
Easypeasy!
  1. EntityFrameWork nuget (it has QueryableExtensions)
  2. przestrzeń nazw = Microsoft.EntityFrameworkCore

Kod zmienił się tak

var myContract = await query.Where(c => c.ContractID == _contractID).FirstAsync();
  1. Podpis metody zmieniony z

    Contract GetContract(int contractnumber)

    Do

    async Task<Contract> GetContractAsync(int contractnumber)

  2. Wywołanie metody również miało wpływ: GetContractAsync(123456); zostało wywołane jako GetContractAsync(123456).Result;

  3. Zmieniliśmy go wszędzie w 30 minuty!

Ale architekt kazał nam nie używać biblioteki EntityFrameWork tylko do tego! UPS! drama! Następnie wykonaliśmy niestandardową realizację zadań. Co wiesz jak. Nadal łatwe!

Gdzie teraz? Jest wspaniały szybki film, który moglibyśmy obejrzeć o konwertowaniu połączeń synchronicznych na asynchroniczne w ASP.Net Core , ponieważ jest to prawdopodobnie kierunek, w którym podąży się po przeczytaniu tego.

 2
Author: Blue Clouds,
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-09-21 05:09:07

Używa ich równo do spawania wątków tła do wykonywania długich logika czasu trwania?

Ten artykuł MDSN: programowanie asynchroniczne za pomocą asynchronicznego i oczekującego (C#) wyjaśnia to wprost:

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 wykorzystuje czas na wątek tylko wtedy, gdy metoda jest aktywna.

 1
Author: Dmitry G.,
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
2016-10-04 16:16:30

W poniższym kodzie metoda HttpClient GetByteArrayAsync zwraca zadanie getContentsTask. Zadanie jest obietnicą wytworzenia rzeczywistej tablicy bajtów po zakończeniu zadania. Operator wait jest stosowany do getContentsTask, aby zawiesić wykonywanie w SumPageSizesAsync do czasu zakończenia getContentsTask. W międzyczasie kontrola jest zwracana do wywołującego SumPageSizesAsync. Po zakończeniu getContentsTask wyrażenie wait zostanie obliczone na tablicę bajtów.

private async Task SumPageSizesAsync()
{
    // To use the HttpClient type in desktop apps, you must include a using directive and add a 
    // reference for the System.Net.Http namespace.
    HttpClient client = new HttpClient();
    // . . .
    Task<byte[]> getContentsTask = client.GetByteArrayAsync(url);
    byte[] urlContents = await getContentsTask;

    // Equivalently, now that you see how it works, you can write the same thing in a single line.
    //byte[] urlContents = await client.GetByteArrayAsync(url);
    // . . .
}
 1
Author: lazydeveloper,
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
2017-08-31 18:40:12

Na wyższym poziomie:

1) asynchroniczne słowo kluczowe włącza oczekiwanie i to wszystko, co robi. Słowo kluczowe Async nie uruchamia metody w osobnym wątku. Początkowa metoda f asynchroniczna działa synchronicznie, dopóki nie trafi na czasochłonne zadanie.

2) możesz czekać na metodę, która zwróci zadanie lub zadanie typu T. nie możesz czekać na metodę async void.

3) moment spotkania głównego wątku na czasochłonne zadanie lub gdy rzeczywista praca jest rozpoczęta, główny wątek zwraca do wywołującego bieżącą metodę.

4) jeśli główny wątek widzi oczekiwanie na zadanie, które jest nadal wykonywane, nie czeka na nie i powraca do wywołującego bieżącą metodę. W ten sposób aplikacja pozostaje responsywna.

5) wait on processing task, będzie teraz wykonywane na oddzielnym wątku z puli wątków.

6) Gdy to zadanie zostanie zakończone, cały poniższy kod zostanie wykonany przez oddzielny wątek

Poniżej znajduje się przykładowy kod. Wykonaj go i sprawdź ID wątku

using System;
using System.Threading;
using System.Threading.Tasks;

namespace AsyncAwaitDemo
{
    class Program
    {
        public static async void AsynchronousOperation()
        {
            Console.WriteLine("Inside AsynchronousOperation Before AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
            //Task<int> _task = AsyncMethod();
            int count = await AsyncMethod();

            Console.WriteLine("Inside AsynchronousOperation After AsyncMethod Before Await, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            //int count = await _task;

            Console.WriteLine("Inside AsynchronousOperation After AsyncMethod After Await Before DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            DependentMethod(count);

            Console.WriteLine("Inside AsynchronousOperation After AsyncMethod After Await After DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
        }

        public static async Task<int> AsyncMethod()
        {
            Console.WriteLine("Inside AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
            int count = 0;

            await Task.Run(() =>
            {
                Console.WriteLine("Executing a long running task which takes 10 seconds to complete, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(20000);
                count = 10;
            });

            Console.WriteLine("Completed AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            return count;
        }       

        public static void DependentMethod(int count)
        {
            Console.WriteLine("Inside DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId + ". Total count is " + count);
        }

        static void Main(string[] args)
        {
            Console.WriteLine("Started Main method, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            AsynchronousOperation();

            Console.WriteLine("Completed Main method, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            Console.ReadKey();
        }

    }
}
 1
Author: ABajpai,
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-05 17:38:51

Odpowiedzi tutaj są przydatne jako ogólne wskazówki dotyczące wait/async. Zawierają również pewne szczegóły dotyczące sposobu połączenia wait / async. Chciałbym podzielić się z wami praktycznym doświadczeniem, które powinniście znać przed użyciem tego wzoru.

Termin "wait" jest dosłowny, więc jakikolwiek wątek, w którym go wywołasz, będzie czekał na wynik metody przed kontynuowaniem. Na wątku jest to katastrofa. Wątek pierwszoplanowy niesie ciężar konstruowania aplikacji, w tym widoki, modele widoku, początkowe animacje i cokolwiek innego, co zostało uruchomione z tymi elementami. Więc kiedy czekasz na pierwszoplanowy wątek, ty stop aplikacja. Użytkownik czeka i czeka, gdy nic się nie wydarzy. Zapewnia to negatywne wrażenia użytkownika.

Z pewnością możesz poczekać na wątek tła za pomocą różnych środków:

Device.BeginInvokeOnMainThread(async () => { await AnyAwaitableMethod(); });

// Notice that we do not await the following call, 
// as that would tie it to the foreground thread.
try
{
Task.Run(async () => { await AnyAwaitableMethod(); });
}
catch
{}

Pełny kod tych uwag znajduje się na https://github.com/marcusts/xamarin-forms-annoyances . zobacz Rozwiązanie o nazwie Waitasyncantipattern.sln.

Strona GitHub zawiera również linki do bardziej szczegółowej dyskusji na ten temat.

 0
Author: Stephen Marcus,
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-04-13 22:47:14

Poniżej znajduje się kod, który odczytuje plik Excela otwierając okno dialogowe, a następnie używa asynchronicznego i czeka na uruchomienie asynchronicznego kodu, który odczytuje jeden po drugim wiersz z Excela i wiąże się z siatką

    namespace EmailBillingRates
{
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        lblProcessing.Text = "";
    }

    private async void btnReadExcel_Click(object sender, EventArgs e)
    {
        string filename = OpenFileDialog();

        Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
        Microsoft.Office.Interop.Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(filename);
        Microsoft.Office.Interop.Excel._Worksheet xlWorksheet = xlWorkbook.Sheets[1];
        Microsoft.Office.Interop.Excel.Range xlRange = xlWorksheet.UsedRange;
        try
        {
            Task<int> longRunningTask = BindGrid(xlRange);
            int result = await longRunningTask;

        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message.ToString());
        }
        finally
        {
            //cleanup  
           // GC.Collect();
            //GC.WaitForPendingFinalizers();

            //rule of thumb for releasing com objects:  
            //  never use two dots, all COM objects must be referenced and released individually  
            //  ex: [somthing].[something].[something] is bad  

            //release com objects to fully kill excel process from running in the background  
            Marshal.ReleaseComObject(xlRange);
            Marshal.ReleaseComObject(xlWorksheet);

            //close and release  
            xlWorkbook.Close();
            Marshal.ReleaseComObject(xlWorkbook);

            //quit and release  
            xlApp.Quit();
            Marshal.ReleaseComObject(xlApp);
        }

    }

    private void btnSendEmail_Click(object sender, EventArgs e)
    {

    }

    private string OpenFileDialog()
    {
        string filename = "";
        OpenFileDialog fdlg = new OpenFileDialog();
        fdlg.Title = "Excel File Dialog";
        fdlg.InitialDirectory = @"c:\";
        fdlg.Filter = "All files (*.*)|*.*|All files (*.*)|*.*";
        fdlg.FilterIndex = 2;
        fdlg.RestoreDirectory = true;
        if (fdlg.ShowDialog() == DialogResult.OK)
        {
            filename = fdlg.FileName;
        }
        return filename;
    }

    private async Task<int> BindGrid(Microsoft.Office.Interop.Excel.Range xlRange)
    {
        lblProcessing.Text = "Processing File.. Please wait";
        int rowCount = xlRange.Rows.Count;
        int colCount = xlRange.Columns.Count;

        // dt.Column = colCount;  
        dataGridView1.ColumnCount = colCount;
        dataGridView1.RowCount = rowCount;

        for (int i = 1; i <= rowCount; i++)
        {
            for (int j = 1; j <= colCount; j++)
            {
                //write the value to the Grid  
                if (xlRange.Cells[i, j] != null && xlRange.Cells[i, j].Value2 != null)
                {
                     await Task.Delay(1);
                     dataGridView1.Rows[i - 1].Cells[j - 1].Value =  xlRange.Cells[i, j].Value2.ToString();
                }

            }
        }
        lblProcessing.Text = "";
        return 0;
    }
}

internal class async
{
}

} `

 0
Author: Zaheer Abbas,
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-04-26 10:51:54

Async / Wait

Actually Async / wait to para słów kluczowych, które są tylko cukrem składniowym do tworzenia wywołania zwrotnego zadania asynchronicznego.

Weźmy na przykład tę operację:

    public static void DoSomeWork()
    {
        var task = Task.Run(() =>
        {
            // [RUNS ON WORKER THREAD]

            // IS NOT bubbling up due to the different threads
            throw new Exception();
            Thread.Sleep(2000);

            return "Hello";
        });

        // This is the callback
        task.ContinueWith((t) => {
            // -> Exception is swallowed silently
            Console.WriteLine("Completed");

            // [RUNS ON WORKER THREAD]
        });
    }

Ta metoda ma wady Serwal. Błędy nie są przekazywane dalej i jest to niezwykle trudne do odczytania. Ale Async i czekam na pomoc:

    public async static void DoSomeWork()
    {
        var result = await Task.Run(() =>
        {
            // [RUNS ON WORKER THREAD]

            // IS bubbling up
            throw new Exception();
            Thread.Sleep(2000);

            return "Hello";
        });

        // every thing below is a callback 
        // (including the calling methods)

        Console.WriteLine("Completed");

    }

Wywołania oczekujące muszą być w metodach asynchronicznych. Ma to pewne zalety:

  • zwraca wynik
  • tworzy automatycznie wywołanie zwrotne
  • Sprawdzanie błędów w callstacku (tylko do zera-oczekiwanie na połączenia w callstacku)]}
  • czeka na wynik
  • zwalnia główny wątek
  • uruchamia callback na głównym wątku
  • używa wątku roboczego z threadpool dla zadania
  • sprawia, że kod jest łatwy do odczytania
  • i wiele więcej

Uwaga : asynchroniczne i oczekujące są używane Z asynchroniczne wywołania Nie , aby je wykonać. Musisz użyć Task Libary do tego, jak zadanie.Run ().

Oto porównanie rozwiązań wait I none wait

Jest to rozwiązanie asynchroniczne none:

    public static long DoTask()
    {
        stopWatch.Reset();
        stopWatch.Start();

        // [RUNS ON MAIN THREAD]
        var task = Task.Run(() => {
            Thread.Sleep(2000);
            // [RUNS ON WORKER THREAD]
        });
        Thread.Sleep(1000);
        // goes directly further
        // WITHOUT waiting until the task is finished

        // [RUNS ON MAIN THREAD]

        stopWatch.Stop();
        // 50 milliseconds
        return stopWatch.ElapsedMilliseconds;
    }

Jest to metoda asynchroniczna:

    public async static Task<long> DoAwaitTask()
    {
        stopWatch.Reset();
        stopWatch.Start();

        // [RUNS ON MAIN THREAD]

        await Task.Run(() => {
            Thread.Sleep(2000);
            // [RUNS ON WORKER THREAD]
        });
        // Waits until task is finished

        // [RUNS ON MAIN THREAD]

        stopWatch.Stop();
        // 2050 milliseconds
        return stopWatch.ElapsedMilliseconds;
    }

Można actually wywołać metodę asynchroniczną bez słowa kluczowego wait, ale oznacza to, że każdy wyjątek tutaj jest połykany w trybie release:

    public static Stopwatch stopWatch { get; } = new Stopwatch();

    static void Main(string[] args)
    {
        Console.WriteLine("DoAwaitTask: " + DoAwaitTask().Result + " ms");
        // 2050 (2000 more because of the await)
        Console.WriteLine("DoTask: " + DoTask() + " ms");
        // 50
        Console.ReadKey();
    }

Asynchroniczne i oczekujące nie są przeznaczone dla równoległych Informatyka. Są one używane, aby nie blokować głównego wątku. Jeśli chodzi o asp.net lub Windows applicantions. Blokowanie głównego wątku z powodu połączenia sieciowego jest złą rzeczą. Jeśli to zrobisz, Twoja aplikacja przestanie odpowiadać lub może ulec awarii.

Sprawdź ms docs , aby uzyskać kilka przykładów.

Mam nadzieję, że to pomoże;

 0
Author: Hakim,
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-09-27 17:45:43