【问题标题】:Is it wrong or bad practice to use Task.Run inside a void function?在 void 函数中使用 Task.Run 是错误的还是不好的做法?
【发布时间】:2019-07-16 14:54:05
【问题描述】:

我正在尝试创建一种“即发即弃”的函数,我不关心函数的完成或结果。为了做到这一点,我在该函数的主体中使用Task.Run(),这样我就可以同时运行它并立即从它返回。

我认为值得一提的是,它运行的是一个 IIS 应用程序。

类似这样的:

void ReallyImportantFunction()
{
    //Do really important work
        NotSoImportantWork("some data");
    //Do really important work

}

void NotSoImportantWork(string data)
{
    Task.Run(() =>
    {
        try
        {
            //Do something here with the data   
        }
        catch (Exception ex)
        {
            //Log exception do not throw

        }


    });
}

【问题讨论】:

标签: c# concurrency task


【解决方案1】:

如果没有更多信息,很难回答这个问题,但我认为您误解了Task.Run() 和异步代码的使用。如果它是不重要的工作,并且您不关心结果或完成,您可能会问是否需要首先在此处运行它。其次,Task.Run() 通常用于执行长时间运行的代码,否则可能会阻塞 UI 线程。如果您正在进行数据库调用或写入文件系统,则将此逻辑放入任务中可能是有意义的。一个例子是

void ReallyImportantFunction()
{
    try
    {
        //Do really important work
        Task.Run(() => NotSoImportantWork("some data"));
        //Do really important work

    }
    catch (Exception ex)
    {
        / Handle the exception
    }
}

void NotSoImportantWork(string data)
{
    //Do something here with the data   
}

但是,如果您确实曾经使用您正在计算的任何东西,或者您的计算曾经有任何副作用或突变,这会使您面临数据竞争。如果你说的是真的而且你从来没有看结果,我可能会问为什么它在开始的方法中。如果您永远不会使用它们,为什么要在重要的事情中间计算真正不重要的事情呢?如果您正在使用结果,或者改变您需要的东西,那么您的代码正确地等待结果是有意义的。

async void ReallyImportantFunction()
{
    try
    {
        //Do really important work
        var myResult = await IOIntensiveWork("some data");
        //Do really important work
    }
    catch (Exception ex)
    {
        // Handle the exception
    }
}

Task<MyResult> IOIntensiveWork(string data)
{
    //Do something here with the data   
}

如果您也可以避免使用async void 方法,它通常会更干净,尽管它不一定有问题。请记住始终检查异常情况。

编辑:根据您在 cmets 中所写的内容,我认为将您的 NotSoImportantWork() 包装在一个任务中是有意义的。这并不是因为它不重要,而是因为您显然是在进行网络调用,并且在与您无法控制的服务通信时可能会出现各种问题。

因此,您可以只使用ReallyImportantFunction() 中的Task.Run(() =&gt; NotSoImportantWork("..."));,但请注意捕获异常的位置以及如果发生异常,您的代码可能会退出的位置。我可能更愿意在那里而不是在NotSoImportantWork() 中启动Task.Run(),因为您可能会使用Task.Run(...).ConfigureAwait(false); 从代码中挤出最后一点性能(这在很大程度上取决于代码的结构)。

根据您从何处启动任务,您可以使用...ConfigureAwait(false); 表示您不需要任务在操作完成后返回到当前上下文。这有时可以提高性能。在有意义的时候尝试并使用它。欲了解更多信息,请查看:When correctly use Task.Run and when just async-await

如果您的代码没有更多的上下文,很难比这更详细。希望对您有所帮助!

【讨论】:

  • NotSoImportantWork 是对托管在另一台机器上的消息代理的网络调用,它记录有关已处理数据的一些信息。每次有新数据包进来时,该信息都会更新,所以如果出现问题我真的不在乎,因为无论如何下一个包都会更新它。
  • 多加点。 RealImportantFunction() 的性能对我们的业务至关重要,因此在其执行中添加尽可能接近 0 毫秒是理想的。 NotSoImportantWork() 是从多个地方调用的,这就是我将 Task.Run 添加到其主体而不是在外部复制的原因。
  • 我刚刚编辑了我的答案以包含一些建议。看看,告诉我你的想法。希望对您有所帮助!
猜你喜欢
  • 1970-01-01
  • 2010-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-17
  • 2015-05-09
  • 2017-12-10
  • 2021-12-31
相关资源
最近更新 更多