在 void 函数中使用 Task.Run 是错误还是不良做法?



>我正在尝试创建一种"即发即弃"函数,我不关心函数的完成或结果。为了做到这一点,我在该函数的主体中使用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
}

});
}

如果没有更多信息,很难回答这个问题,但我认为您误解了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方法,它通常会更干净,尽管它不一定有问题。请记住始终检查异常。

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

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

根据启动任务的位置,您可以使用...ConfigureAwait(false);表示操作完成后不需要任务返回到当前上下文。这有时可以提高性能。只要有意义,就尝试使用它。有关更多信息,请查看以下内容:正确使用 Task.Run 时以及何时只是 async-await

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

最新更新