Backgroundworker和TPL的Task有相同的ManagedThreadID吗?

时间:2010-09-17 12:02:33

标签: c# .net multithreading task-parallel-library

我有一个Backgroundworker,其目的是在后台顺序运行作业。现在,一项工作以多线程方式实现。这意味着,Backgroundworker将创建多个线程。我使用任务并行库,所以我使用Task.Factory.StartNew创建多个任务。

运行任务后,Backgroundworker等待所有任务完成。

现在我打印Backgroundworker的ManagedThreadID和所有任务'ManagedThreadIDs。我发现BackgroundWorker的ManagedThreadID始终与第一个任务的ManagedThreadID相同。我认为这不应该发生,所以我无法解释。我认为Backgroundworker的线程必须与它创建的所有任务不同,因此ManagedThreadID必须彼此不同。

任何人都能解释为什么会出现这种情况吗?非常感谢你。

编辑:

代码与此类似:

Backgroundworker.Run(){
    // Print Thread.CurrentThread.ManagedThreadID.
    var task = Task.Factory.StartNew(action1); // action1, action2 also print ManagedThredID.
    taskList.Add(task);
    task = Task.Factory.StartNew(action2);
    taskList.Add(task);
    ... // Several other tasks.

    foreach(var task in taskList) task.Wait();
}

您会发现一个任务与Backgroundworker具有相同的ManagedThreadID。

4 个答案:

答案 0 :(得分:5)

我会在这里继续思考并猜测TPL足够聪明,可以重用BackgroundWorker线程。由于worker等待所有任务完成,因此在同一个线程中运行一个任务可能是一个优化。

通过进一步调查,您所看到的是Task.Wait方法的预期行为的结果。您可以在并行编程团队博客上的Task.Wait and "Inlining"阅读更多内容。

  

如果正在等待的任务有   已经开始执行,等待必须   块。但是,如果还没有开始   执行,等待也许能够拉动   调度程序中的目标任务   它排队并执行它   内联当前线程。

答案 1 :(得分:2)

后台工作程序从线程池和TPL中提取线程。可能发生的是后台工作程序启动,它从池中抽取一个线程并触发TPL线程并立即将线程返回到池中。当TPL的第一个任务被执行时,TPL从池中抽取一个线程,它发现它选择了与后台工作者曾经使用过的线程相同的线程。

当然,这只是一个无法验证的假设,因为你没有展示你的代码。

答案 2 :(得分:2)

你偶然发现的当然不是问题,而是一个功能(优化):TPL正在尽可能多地重用线程。

创建任务时,它不会立即/永久地与线程关联。任务是放在队列中的作业,队列由工作线程提供服务。因此可能是Bgw Task被挂起并且它的线程返回到池中,或者更直接地可以通过Wait()来完成:

// thread A
var t1 = Task.Startnew(...);
var t2 = Task.Startnew(...);
t1.Wait();  // Thread A is idle/available so Wait can execute t1
t2.Wait();  

答案 3 :(得分:1)

使用TaskCreationOptions.LongRunning避免重新循环后台工作程序。