async / wait-kiedy zwrócić zadanie vs void?

W jakich scenariuszach można by użyć

public async Task AsyncMethod(int num)

Zamiast

public async void AsyncMethod(int num)

Jedyny scenariusz, który mogę wymyślić, to jeśli potrzebujesz zadania, aby móc śledzić jego postępy.

Dodatkowo, w poniższej metodzie, czy słowa kluczowe async i wait są niepotrzebne?

public static async void AsyncMethod2(int num)
{
    await Task.Factory.StartNew(() => Thread.Sleep(num));
}
Author: Boiethios, 2012-08-27

6 answers

1) normalnie, chcesz zwrócić Task. Głównym wyjątkiem powinno być, gdy trzeba mieć typ zwracania void (dla zdarzeń). Jeśli nie ma powodu, aby nie mieć rozmówcy await swoje zadanie, po co je odrzucać?

2) async Metody zwracające {[3] } są wyjątkowe w innym aspekcie: reprezentują operacje asynchroniczne najwyższego poziomu i mają dodatkowe reguły, które wchodzą w grę, gdy zadanie zwraca wyjątek. Najprostszym sposobem jest pokazanie różnicy jest przykład:

static async void f()
{
    await h();
}

static async Task g()
{
    await h();
}

static async Task h()
{
    throw new NotImplementedException();
}

private void button1_Click(object sender, EventArgs e)
{
    f();
}

private void button2_Click(object sender, EventArgs e)
{
    g();
}

private void button3_Click(object sender, EventArgs e)
{
    GC.Collect();
}

f'wyjątek S jest zawsze "obserwowany". Wyjątek, który pozostawia metodę asynchroniczną najwyższego poziomu, jest po prostu traktowany jak każdy inny nieobsługiwany wyjątek. g wyjątek nigdy nie jest obserwowany. Kiedy garbage collector przychodzi, aby wyczyścić zadanie, widzi, że zadanie spowodowało wyjątek i nikt nie obsłużył wyjątku. Kiedy to się stanie, TaskScheduler.UnobservedTaskException handler biegnie. Nie powinieneś do tego dopuścić. Aby użyć swojego przykładu,

public static async void AsyncMethod2(int num)
{
    await Task.Factory.StartNew(() => Thread.Sleep(num));
}

Tak, użyj async i await tutaj upewniają się, że twoja metoda nadal działa poprawnie, jeśli zostanie wyrzucony wyjątek.

Aby uzyskać więcej informacji zobacz: http://msdn.microsoft.com/en-us/magazine/jj991977.aspx

 315
Author: suizo,
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-03 12:07:19

Natknąłem się na bardzo przydatny artykuł o async i void napisany przez Jérôme Laban: http://www.jaylee.org/post/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void.aspx

Najważniejsze jest to, że async+void może spowodować awarię systemu i zwykle powinien być używany tylko w programach obsługi zdarzeń pobocznych UI.

Powodem tego jest kontekst synchronizacji używany przez AsyncVoidMethodBuilder, jako żaden w tym przykładzie. Gdy nie ma otoczenie Kontekst synchronizacji, każdy wyjątek, który nie jest obsługiwany przez ciało metody asynchronicznej jest retrownowane na wątku. While pozornie nie ma innego logicznego miejsca, w którym takie niespokojne wyjątek może być wyrzucony, niefortunnym efektem jest to, że proces jest zakończone, ponieważ nieobsługiwane wyjątki na wątku skutecznie zakończyć proces od. NET 2.0. Możesz przechwycić wszystkie nieobsługiwane wyjątki za pomocą AppDomain.UnhandledException event, ale nie ma możliwości odzyskania procesu z tego zdarzenia.

Podczas pisania programów obsługi zdarzeń UI, metody async void są w jakiś sposób bezbolesne, ponieważ wyjątki są traktowane tak samo jak w metody nie-asynchroniczne; są one rzucane na dyspozytora. Jest możliwość odzyskania od takich wyjątków, z jest więcej niż poprawne w większości przypadków. Jednak poza procesorami obsługi zdarzeń UI, asynchroniczna pustka metody są w jakiś sposób niebezpieczne w użyciu i mogą nie być łatwe do znalezienia.

 27
Author: Davide Icardi,
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-04-11 15:40:55

Mam jasne pojęcie z tych wypowiedzi.

  1. asynchroniczne metody void mają inną semantykę obsługi błędów. Gdy wyjątek jest wyrzucany z zadania asynchronicznego lub metody zadania asynchronicznego, wyjątek ten jest przechwytywany i umieszczany na obiekcie zadania. W przypadku metod async void nie ma obiektu Task, więc wszelkie wyjątki wyrzucane z metody async void będą wywoływane bezpośrednio na SynchronizationContext(SynchronizationContext reprezentuje lokalizację" gdzie " kod może być wykonany. ) to było aktywna po uruchomieniu metody async void

Wyjątki z metody Async Void nie mogą być przechwytywane za pomocą Catch

private async void ThrowExceptionAsync()
{
  throw new InvalidOperationException();
}
public void AsyncVoidExceptions_CannotBeCaughtByCatch()
{
  try
  {
    ThrowExceptionAsync();
  }
  catch (Exception)
  {
    // The exception is never caught here!
    throw;
  }
}

Wyjątki te można zaobserwować za pomocą AppDomain.UnhandledException lub podobne zdarzenie catch-all dla aplikacji GUI/ASP. NET, ale używanie tych zdarzeń do regularnej obsługi wyjątków jest przepisem na brak konserwacji (powoduje awarię aplikacji).

  1. Metody asynchroniczne mają różną semantykę komponowania. Metody Async zwracające zadanie lub zadanie może być łatwo skomponowany za pomocą czekania, zadania.WhenAny, Zadanie.WhenAll i tak dalej. Metody asynchroniczne zwracające void nie zapewniają łatwego sposobu powiadamiania o zakończeniu kodu wywołującego. Łatwo jest uruchomić kilka metod asynchronicznych, ale nie jest łatwo określić, kiedy zostały zakończone. Metody async void będą powiadamiać o ich SynchronizationContext, gdy zaczną i zakończą, ale niestandardowa SynchronizationContext jest złożonym rozwiązaniem dla zwykłego kodu aplikacji.

  2. Metoda asynchroniczna przydatne podczas używania mechanizmu obsługi zdarzeń synchronicznych, ponieważ wywołują one wyjątki bezpośrednio na SynchronizationContext, co jest podobne do zachowania synchronicznych procedur obsługi zdarzeń

Aby uzyskać więcej informacji sprawdź ten link https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

 14
Author: Nayas Subramanian,
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-25 09:07:33

Myślę, że możesz użyć async void do rozpoczęcia operacji w tle, tak długo, jak będziesz uważać, aby wyłapać wyjątki. Myśli?

class Program {

    static bool isFinished = false;

    static void Main(string[] args) {

        // Kick off the background operation and don't care about when it completes
        BackgroundWork();

        Console.WriteLine("Press enter when you're ready to stop the background operation.");
        Console.ReadLine();
        isFinished = true;
    }

    // Using async void to kickoff a background operation that nobody wants to be notified about when it completes.
    static async void BackgroundWork() {
        // It's important to catch exceptions so we don't crash the appliation.
        try {
            // This operation will end after ten interations or when the app closes. Whichever happens first.
            for (var count = 1; count <= 10 && !isFinished; count++) {
                await Task.Delay(1000);
                Console.WriteLine($"{count} seconds of work elapsed.");
            }
            Console.WriteLine("Background operation came to an end.");
        } catch (Exception x) {
            Console.WriteLine("Caught exception:");
            Console.WriteLine(x.ToString());
        }
    }
}
 3
Author: bboyle1234,
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-16 12:43:42

Problem z wywołaniem async void polega na tym, że nawet nie odzyskasz zadania, nie masz możliwości dowiedzenia się, kiedy zadanie funkcji zostało wykonane (zobacz https://blogs.msdn.microsoft.com/oldnewthing/20170720-00/?p=96655 )

Oto trzy sposoby wywołania funkcji asynchronicznej:

async Task<T> SomethingAsync() { ... return t; }
async Task SomethingAsync() { ... }
async void SomethingAsync() { ... }

We wszystkich przypadkach funkcja jest przekształcana w łańcuch zadań. Różnica polega na tym, co funkcja zwraca.

W pierwszym przypadku funkcja zwraca zadanie to ostatecznie daje t.

W drugim przypadku funkcja zwraca zadanie, które nie ma produktu, ale można nadal czekają na niego, aby wiedzieć, kiedy biegną do zakończenia.

Trzeci przypadek to ten paskudny. Trzeci przypadek jest jak drugi przypadek, z wyjątkiem że nawet nie odzyskasz zadania. Nie możesz wiedzieć, kiedy zadanie funkcji zostało zakończone.

Asynchroniczny przypadek void to " ogień i forget": rozpoczynasz łańcuch zadań, ale nie dbać o to, kiedy jest skończone. Gdy funkcja powróci, wszystko, co wiesz, to to, że wszystko aż do pierwszego oczekiwanie zostało wykonane. Wszystko po pierwszym oczekiwaniu będzie działać w pewnym nieokreślonym momencie w przyszłości, że nie masz dostęp do.

 2
Author: user8128167,
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-06-19 15:31:19

Moja odpowiedź jest prosta you cannon wait void method Błąd CS4008 nie można czekać na "void" TestAsync e:\test\TestAsync\TestAsync\Program.cs

Więc jeśli metoda jest asynchroniczna to lepiej czekać, bo można stracić przewagę asynchroniczną.

 0
Author: Serg Sh,
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-20 16:21:00