我需要保留对Task.Run方法返回的Task的引用吗?

时间:2018-08-08 06:04:15

标签: c# .net async-await task-parallel-library

如果我有一个异步方法:

async Task Process()
{
    while (condition)
    {
        await ...;
    }
}

我需要安排此方法的执行时间。所以我用:

Task.Run(Process);

我是否需要保留Task方法返回的Task.Run对象的引用,以确保Process执行完成?


这里有更多上下文:我需要在应用程序中创建很多(约50K)任务队列。因此,我想创建一个无线程的队列处理设计,并且当队列为空时(因为这些队列中的大多数都是这样),它不花钱(除了内存)。

示例类的要点:https://gist.github.com/hemant-jangid/e990b27507596c086e5651f504d0521f

2 个答案:

答案 0 :(得分:5)

通常,您不应该丢弃Task。这不是要确保任务将运行(它将 1 ),而是要观察异常。如果您不使用Task something ,那么找出错误的唯一方法就是添加一个UnobservedTaskException事件处理程序。不理想。

最好在await / try块中使用catch的代码,或者在您指定的地方注册ContinueWith处理程序,以便在发生故障时调用。 / p>

不幸的是(IMO).NET的行为在4.5左右发生了变化,因此无法观察到的异常不再破坏该过程。这意味着,如果您未能观察到它们,则代码将失败,并且没有办法来跟踪/记录这种情况。


general 中,围绕已经产生Task.Run的方法进行Task是不必要的,而且会适得其反。该方法已经承诺提供Task-为什么将其包装在第二个方法中? (该方法如何以及为什么返回Task是该方法的实现细节,而与调用者无关。)只有在您所调用的方法确实完成了重要 CPU绑定工作并且您(调用方)当前处于“宝贵”上下文中时(例如位于UI线程中),您才应该真正这样做。


1 假定整个过程可以生存足够长的时间,等等。

答案 1 :(得分:0)

为此,我们将不得不更深入地研究任务。任务本质上是线程,在其起源中,任务是为线程池安排的。现在考虑以下报价:

  

任务本质上是线程;但它们是后台线程。   当所有前台都后台线程自动中止   线程完成。因此,如果您对任务不执行任何操作,   程序结束,任务有可能无法完成。

因此您可能会认为,如果在所有前台线程完成后后台线程自动中止,则必须保留对task的引用,实际上,这就是为什么您应始终等待{ {3}}。

但是让我们深入研究this post answer并查看以下行:

  

一旦您没有必要保留对Thread对象的引用   已经启动了线程。线程继续执行,直到   线程过程完成。

这意味着,尽管上面提到,当所有前台线程完成时,后台线程会自动中止,但无需保留对其的引用。

实际上,根据文档,创建任务的正确方法是使用工厂:

  

您还可以使用StartNew方法来创建和启动一个任务   操作。如果存在以下情况,这是创建和启动任务的首选方式   创建和计划不必分开