【问题标题】:Is there any point starting a LongRunning Task if the parent immediately Waits?如果父级立即等待,启动 LongRunning 任务有什么意义吗?
【发布时间】:2020-01-27 09:45:46
【问题描述】:

我正在处理一些遗留代码,这些代码在新线程中重复调用长时间运行的任务:

var jobList = spGetSomeJobIds.ToList();

jobList.ForEach((jobId) =>
{
    var myTask = Task.Factory.StartNew(() => CallExpensiveStoredProc(jobId), 
        TaskCreationOptions.LongRunning);
    myTask.Wait();
});

由于调用线程立即调用Wait 并阻塞直到任务完成,我在Task.Factory.StartNew 代码中看不到任何点。我错过了什么吗? TaskCreationOptions.LongRunning 有什么可以增加价值的东西吗?

【问题讨论】:

  • 如果它执行异步 await 而不是 Wait 那么在某些上下文(释放 UI 线程)中它是有意义的。但是做一个阻塞等待,我不会这么想的。
  • 这将是一种确保CallExpensiveStoredProc 在单独的线程上运行并且不会同时发生两次CallExpensiveStoredProc 调用的方法。
  • @Enigmativity 我应该添加这是一个控制台应用程序,并且只有一个实例会运行,考虑到该约束,您在Task.Factory.StartNew 代码中看到任何值吗?
  • @jonaglon - 如果您关闭应用程序,后台线程也将干净地退出。这可能与此有关。
  • 我认为没有任何意义。

标签: c# multithreading task


【解决方案1】:

As msdn says:

等待任务完成执行。

此外,还有如下声明:

Wait 阻塞调用线程直到任务完成。

所以myTask.Wait(); 看起来是多余的,因为方法CallExpensiveStoredProc 什么都不返回。

作为一个好的做法,在处理数据库操作等异步操作时,最好使用asyncawait 运算符。

更新:

我们拥有的是:

  1. 我们运行LongRunning,因此创建了新线程。 It can be seen in source files.

  2. 然后我们调用myTask.Wait();。这个方法只是等待myTask 完成它的工作。所以所有jobList 迭代都将按顺序执行,而不是并行执行。所以现在我们需要决定我们的工作应该如何执行——顺序执行(case A)还是并行执行(case B)。

案例 A:按顺序执行我们的工作

如果您的工作应该按顺序执行,那么可能会出现几个问题:

  • 如果我们的代码是连续执行的,我们使用多线程做什么?我们的代码应该简洁明了。所以我们可以避免在这种情况下使用多线程
  • 当我们创建一个新线程时,我们会向线程池添加额外的开销。因为线程池试图确定最佳线程数,并且每个核心至少创建一个线程。这意味着当所有线程池线程都忙时,任务可能会等待(在极端情况下无限长),直到它真正开始执行。

综上所述,在这种情况下创建新的Thread 没有任何好处,尤其是使用LongRunning 枚举的新线程。

案例 B:我们的工作并行执行

如果我们的目标是并行运行所有作业,则应该消除myTask.Wait();,因为它使代码按顺序执行。

要测试的代码:

var jobs = new List<int>(){1, 2, 3 };
jobs.ForEach(j => 
   {
       var myTask = Task.Factory.StartNew(() => 
       {
           Console.WriteLine($"This is a current number of executing task: { j }");
           Thread.Sleep(5000); // Imitation of long-running operation
           Console.WriteLine($"Executed: { j }");
       },  TaskCreationOptions.LongRunning);
       myTask.Wait();
    });
Console.WriteLine($"All jobs are executed");

总结在这种情况下B,创建新线程没有任何好处,尤其是使用LongRunning枚举的新线程。 Because this is an expensive operation in the time it takes to be created and in memory consumption.

【讨论】:

  • 这个答案中没有任何内容可以直接解决这个问题,“如果父级立即等待,启动 LongRunning 任务有什么意义吗?”
  • @Enigmativity 感谢您的回复。但是,我写了So myTask.Wait(); looks redundant as method CallExpensiveStoredProc returns nothing.。不合适吗?
  • 那句话没有回答这个问题。事实上,这实际上是不真实的。任务不返回任何内容并调用 .Wait() 是完全可以的。
  • @Enigmativity 感谢您的回复!抱歉,.Wait() 会阻塞调用线程,直到任务完成。你能说一下这样做的好处吗?
  • 但是您的回答并没有说明有什么好处或没有什么好处。问题是“如果父级立即等待,启动 LongRunning 任务有什么意义吗?”你还没回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-27
  • 1970-01-01
  • 1970-01-01
  • 2021-01-08
  • 1970-01-01
  • 1970-01-01
  • 2016-01-10
相关资源
最近更新 更多