代码之家  ›  专栏  ›  技术社区  ›  Hemant

是否需要保留对“Task.Run”方法返回的“Task”的引用?

  •  0
  • Hemant  · 技术社区  · 6 年前

    如果我有异步方法:

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

    我需要安排这个方法的执行。所以我用:

    Task.Run(Process);
    

    我需要保留 Task 对象返回者 Task.Run 方法以确保 Process 执行到完成?


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

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

    2 回复  |  直到 6 年前
        1
  •  5
  •   Damien_The_Unbeliever    6 年前

    一般来说,你不应该扔掉 Task s、 这不是要确保任务将运行(它将 1个 ),但大约 观察异常 . 如果你不这样做 某物 任务 那么,发现问题的唯一方法是添加 UnobservedTaskException 事件处理程序。不太理想。

    最好有代码 await 它在一个 try / catch 阻止或注册 ContinueWith 指定错误时应调用的处理程序。

    不幸的是(IMO),.NET的行为在4.5左右发生了变化,因此未被发现的异常不再破坏进程。这意味着如果你没有观察到它们,你就得到了失败的代码 没有办法 追踪/记录这种情况。


    一般的 ,正在做 Task.Run 在已经生成 任务 是不必要的,而且会适得其反。这种方法已经承诺 任务 -为什么用第二个包起来?(该方法返回 任务 是该方法的实现细节,与调用方无关)。只有当你调用的方法 重要的 CPU绑定的工作和您(调用者)当前处于一个“宝贵的”上下文中——比如在UI线程上。


    1个 假设整个过程能持续足够长的时间等。

        2
  •  0
  •   Barr J    6 年前

    为此,我们必须更深入地研究任务。任务本质上是线程,在其起源中,任务是为线程池调度的。现在考虑这句话:

    任务本质上是线程;但它们是后台线程。 当所有前台线程 螺纹完成。所以,如果你对任务和 程序结束,任务有可能无法完成。

    因此,您可能会认为,如果后台线程在所有前台线程完成时自动中止,则必须保留对 task ,实际上,这就是为什么您应该始终等待 this post answer .

    然而 让我们深入到 Thread documentation 看看这一行:

    一旦您 已经启动线程。线程继续执行,直到 线程过程已完成。

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

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

    您还可以使用StartNew方法在一个 操作。这是创建和启动任务的首选方法,如果 创建和调度不必分开