异步警告让我感到困惑

时间:2018-06-09 04:04:27

标签: c# asynchronous warnings

这不是调试类型的问题,我只是在asycnchronous编程领域寻找一个特定的教育领域,我认为这里不在家。 / p>

我正在编写一个程序,我需要它来定期拨打电话,同时还要执行其他功能。我查找了如何编写一个异步方法来实现这一点,并实际上让它工作。

让我感到困惑的是,当我从我的Main方法调用它时,我得到一个警告,说我应该使用await关键字让程序等待方法调用完成,否则我可能无法获得预期的行为这对我来说很奇怪。我认为,编写异步方法的关键在于让它运行,然后继续前进而不等待它完成,因此注意警告会破坏目的。另一方面,我并不傲慢地认为我比开发Visual Studio的专业人员更了解并添加了警告,因此必须有更多情况下添加await关键字更有意义。

我的问题是:通常使用的异步方法如何保证听到此警告?

编辑:人们请求代码和警告的特定文本,所以:

异步方法:

public static async Task FindPairs(TimeSpan interval, CancellationToken cancellationToken)
            {
            while (true)
                {
                lock (relevantVariable)
                    {
                    doStuffEveryInterval();
                    }
                await Task.Delay(interval, cancellationToken);
                }
            }

警告是这样的:"因为没有等待这个调用,所以在调用完成之前继续执行当前方法。考虑应用“等待”#39;运算符到调用的结果。当前方法调用异步方法,该方法返回任务或任务,并且不会将await运算符应用于结果。对异步方法的调用启动异步任务。但是,由于未应用await运算符,程序将继续运行,而无需等待任务完成。在大多数情况下,这种行为并不是您所期望的。通常,调用方法的其他方面取决于调用的结果,或者最少,在从包含调用的方法返回之前,调用的方法应该完成。

同样重要的问题是在被调用的异步方法中引发的异常会发生什么。在返回任务或任务的方法中引发的异常存储在返回的任务中。如果您没有等待任务或明确检查异常,则异常将丢失。如果等待任务,则重新抛出异常。

作为最佳做法,您应该始终等待通话。

只有当您确定不想等待异步调用完成并且被叫方法不会引发任何异常时,才应考虑禁止警告。在这种情况下,您可以通过将调用的任务结果分配给变量来抑制警告。"

1 个答案:

答案 0 :(得分:8)

  

我认为,编写异步方法的关键是让它运行,然后继续前进而不等待它完成

那你为什么await Delay,如果那是你的信仰? Delay返回任务;你开始这项任务,你肯定要在它完成之前继续前进,然后再次进行下一次循环迭代?

当然不是。那将击败延迟的整个点,如果它以异步方式运行并且没有人等待它就完成了。

await究竟是什么意思?它意味着它:异步等待。即:此工作流程在此任务完成之前无法继续,因此如果未完成,请查找其他工作并稍后返回

这就是为什么异步方法的调用者通常会await结果的原因。调用者异步调用您,因为他们认为工作流程需要一些时间才能完成,并且他们可以让他们的调用者做更多的工作,而他们正在等待您的方法异步完成。

通常做什么,但你的方法不正常。 您的方法永远无法正常完成!如果您使用了await这种方法,那么您一直等到它,(因为它被取消)直到它正常完成,因为它没有正常完成!

因此,您的方法返回的await任务可能在实践中永远等待,这不是您想要的。

因此,在这种情况下,您可以忽略或取消警告。但在正常情况下,您正在调用方法,因为您要么需要其副作用或结果,并且您无法继续工作流程直到获得它。因此,您await这项任务,以便您的来电者可以在您等待您的被叫方工作流程完成时完成更多工作。

在编写更多异步代码之前,请确保绝对清除。 await是异步工作流程的排序操作。这意味着"此工作流程在此任务完成之前不会继续;在你等待的时候去寻找其他的事情,当我们继续进行时,我们会回来#34;。

将其与"正常"进行比较打电话给正常的方法。 x = foo();表示"在完成对foo的调用之前,此工作流程不会继续;什么都不做,只是运行foo完成"。我们习惯于称​​同步等待结果,我们甚至不再考虑它了。

这个问题指出了C#类型系统存在更大的设计问题。非泛型Task在逻辑上是"异步void&#34 ;;也就是说,工作流完成,但未完成对于永远不会正常返回但可能抛出的方法,C#没有类型系统概念。您可以想象一个void的特殊版本,可能是void never,这种方法中返回或具有可达终点是错误的。

您的工作流程在逻辑上是一个永不执行的任务" - 这是一个无法正常完成的异步工作流程。如果编译器知道那么它可以抑制警告(并且它可能会对同步调用never void方法产生警告,这些方法后面有无法访问的代码。)但是编译器没有我知道,因为这个概念首先不属于类型系统。从逻辑上讲,它可能是,但我认为C#团队有更紧迫的问题。