是否有多个Task.Run的开销在等待而没有返回?

时间:2020-04-23 19:54:38

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

已创建的1000个任务中,假设taskCompletionSource在代码的其他部分中成功完成,则只有很少(10)个任务可以完成。这意味着ProcessWorkItemAsync完成仅将被打印10次。

代码:

for (var i = 0;i<1000; i++)
{
     Task.Run(() => {
      await ProcessWorkItemAsync(); 
      Console.WriteLine("ProcessWorkItemAsync finished");
     }); 

}

async Task<TaskCompletionSource<int>> ProcessWorkItemAsync()
{
    return new TaskCompletionSource<int>();
}
  1. 是否有990项CPU开销未完成且处于困境?
    • 从我阅读的内容来看,线程不会被阻塞,它将返回到线程池,因此从CPU角度看,似乎没有任何开销。我还缺少什么吗?
  2. 是否有内存开销?
    • 由于存储了调用堆栈,因为点网必须跟踪返回的位置。
    • 我假设这些调用堆栈将存储在堆中,并产生内存成本?

1 个答案:

答案 0 :(得分:4)

已创建的1000个任务中,假设taskCompletionSource在代码的其他部分中成功完成,则只有很少(10)个任务可以完成。这意味着ProcessWorkItemAsync完成仅将打印10次。

您发布的代码没有该行为。发布的代码将打印"ProcessWorkItemAsync finished" 1000次,所有任务几乎立即完成。对于此答案的其余部分,我将解决问题并忽略代码。

是否有990项CPU开销未完成且处于困境?

否。

从我所读的内容来看,线程不会被阻塞,它将返回到线程池,因此从CPU的角度看,似乎没有任何开销。我还缺少其他东西吗?

任务不是线程。您实际上没有1000个任务的事实意味着有或曾经有1000个线程。

Task.Run确实将工作加到线程池中,但是将异步任务与Task.Run一起使用时,只要await必须异步等待,该线程池中的线程就会返回到线程池中。任务是否完成无关紧要。

有内存开销吗?

是的。任务是对象,就像其他任何引用类型一样。它们可以像其他引用类型一样扎根。而且,如果从未清除(完成)它们,则它们可以像其他任何引用类型一样a resource leak

因为要存储调用堆栈,所以点网必须跟踪返回的位置。我假设这些调用堆栈将存储在堆中并产生内存消耗?

排序。不会捕获或存储调用堆栈。该任务仅存储其继续。从逻辑上讲,您可以将其视为“调用堆栈”,但深度只有1。因此,每个任务将使await使用它的所有代码保持有效。