简体   繁体   English

卡在异步等待线程中

[英]Stuck with async await thread

In constructor I want to call one method type :在构造函数中,我想调用一种方法类型:

private async Task OnLoadPrometDanKorisnikDatum

and I want to wait that method while its finish, and I have more method(3) like this and I want to call this 3 methods in background thread and don't wait him to finish, just want to wait first method.我想在该方法完成时等待该方法,并且我有更多这样的方法(3),我想在后台线程中调用这 3 个方法,不要等待他完成,只想等待第一个方法。 And I want to them executing parallel.我希望它们并行执行。 I have methods async Task,and in constructor of view model I call like this我有异步任务方法,并且在视图模型的构造函数中我这样调用

OnLoadPrometDanKorisnikDatum(KorisnikID, PomocnaDnDDatnaDat, 
    DatumVrednost).Wait();
OnLoadPrometNedelja(KorisnikID, PomocnaDnDDatnaDatNedelja).Wait();

if I don't place .Wait() on the end, program doesn't work.如果我不把 .Wait() 放在最后,程序就不起作用。 I see in debug mode they run asynchronly, but time spent tell me that they sub(one method time + second method time + ....).我在调试模式下看到它们异步运行,但是花费的时间告诉我它们是子(一种方法时间 + 第二种方法时间 + ....)。 Can someone help me, this is for me very stuf...有人可以帮助我吗,这对我来说非常重要...

Answer回答

The best way to handle your scenario is to use async void .处理您的场景的最佳方法是使用async void

I recommend first reading the Explanation section below to fully understand the best practices around async void .我建议首先阅读下面的Explanation部分,以充分了解有关async void的最佳实践。

public MyConstructor()
{
    ExecuteAsyncMethods();
}

async void ExecuteAsyncMethods()
{ 
    try
    {
        await OnLoadPrometDanKorisnikDatum(KorisnikID, PomocnaDnDDatnaDat, DatumVrednost);
        await OnLoadPrometNedelja(KorisnikID, PomocnaDnDDatnaDatNedelja);
    }
    catch(Exception e)
    {
        //Handle Exception
    }
}

Explanation解释

Many C# devs are taught "Never use async void ", but this is one of the few use-cases for it.许多 C# 开发人员都被教导“永远不要使用async void ”,但这是为数不多的用例之一。

Yes async void can be dangerous and here's why:是的async void可能很危险,原因如下:

  • Cannot await an async avoid method不能await async avoid方法
  • Can lead to race conditions可能导致竞争条件
  • Difficult to catch an Exception thrown by async void methods难以捕获async void方法抛出的Exception
    • Eg the following try/catch block will not catch the Exception thrown here:例如,下面的try/catch块不会捕获这里抛出的Exception
public MyConstructor()
{
    try
    {
        //Cannot await `async void`
        AsyncVoidMethodWithException();
    }
    catch(Exception e)
    {
        //Will never catch the `Exception` thrown in  `AsyncVoidMethodWithException` because `AsyncVoidMethodWithException` cannot be awaited
    }

    //code here will be executing by the time `AsyncVoidMethodWithException` throws the exception
}

async void AsyncVoidMethodWithException()
{
    await Task.Delay(2000);
    throw new Exception();
}

That being said, as long as we wrap the contents of our entire async void in a try/catch block, we will be able to catch the exception, like so:话虽如此,只要我们将整个async void的内容包装在try/catch块中,我们就能够捕获异常,如下所示:

public MyConstructor()
{
    AsyncVoidMethodWithException();
}

async void AsyncVoidMethodWithException()
{
    try
    {
        await Task.Delay(2000);
        throw new Exception();
    }
    catch(Exception e)
    {
        //Exception will be caught and successfully handled 
    }
}

SafeFireAndForget SafeFireAndForget

I created a library to help with this and its additional benefit is that it avoids writing async void code that could be potentially misused by future devs.我创建了一个库来帮助解决这个问题,它的额外好处是它避免了编写可能被未来开发人员误用的async void代码。

It's open source and also available on NuGet:它是开源的,也可以在 NuGet 上获得:

SafeFireAndForget SafeFireAndForget

SafeFireAndForget allows us to safely execute a Task whilst not blocking the calling thread and without waiting for it to finish before moving to the next line of code. SafeFireAndForget允许我们在不阻塞调用线程的情况下安全地执行Task ,并且在移动到下一行代码之前无需等待它完成。

Below is a simplified version of SafeFireAndForget that you can add to your project.下面是SafeFireAndForget的简化版本,您可以将其添加到您的项目中。

However, I recommend copy/pasting its complete source code or adding its NuGet Package to your library to get a more robust implementation但是,我建议复制/粘贴其完整的源代码或将其NuGet 包添加到您的库中以获得更强大的实现

public static async void SafeFireAndForget<TException>(this Task task, Action<TException> onException = null, bool continueOnCapturedContext = false) where TException : Exception
{
    try
    {
        await task.ConfigureAwait(continueOnCapturedContext);
    }
    catch (TException ex) when (onException != null)
    {
        onException(ex);
    }
}

Using SafeFireAndForget使用 SafeFireAndForget

To use SafeFireAndForget , append it to your method call like so:要使用SafeFireAndForget ,请将其附加到您的方法调用中,如下所示:

OnLoadPrometDanKorisnikDatum(KorisnikID, PomocnaDnDDatnaDat, DatumVrednost).SafeFireAndForget();
OnLoadPrometNedelja(KorisnikID, PomocnaDnDDatnaDatNedelja).SafeFireAndForget();

To handle any Exception thrown by that Task , use onException .要处理该Task抛出的任何Exception ,请使用onException Here's an example that prints the Exception to the Debug Console:这是将Exception打印到调试控制台的示例:

OnLoadPrometDanKorisnikDatum(KorisnikID, PomocnaDnDDatnaDat, DatumVrednost).SafeFireAndForget(ex => Debug.WriteLine(ex));
OnLoadPrometNedelja(KorisnikID, PomocnaDnDDatnaDatNedelja).SafeFireAndForget(ex => Debug.WriteLine(ex));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM