C# 后台工作人员和第三方物流公司';的任务是否具有相同的ManagedThreadID?

C# 后台工作人员和第三方物流公司';的任务是否具有相同的ManagedThreadID?,c#,.net,multithreading,task-parallel-library,C#,.net,Multithreading,Task Parallel Library,我有一个后台工作人员,其目的是在后台按顺序运行作业。现在一个作业是以多线程方式实现的。这意味着,Backgroundworker将创建几个线程。我使用任务并行库,因此我使用Task.Factory.StartNew创建多个任务 任务运行后,Backgroundworker将等待所有任务完成 现在我打印Backgroundworker的ManagedThreadID和所有任务的ManagedThreadID。我发现BackgroundWorker的ManagedThreadID始终与第一个任务的M

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

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

现在我打印Backgroundworker的ManagedThreadID和所有任务的ManagedThreadID。我发现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。

后台工作程序从线程池以及TPL中提取线程。可能发生的情况是,后台工作程序启动后,它会从池中提取一个线程并激发TPL线程,然后立即将该线程返回到池中。在执行TPL的第一个任务时,TPL从池中绘制了一个线程,并且碰巧它选择了与后台工作人员曾经使用的线程相同的线程


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

我会在这里冒险,猜测TPL足够聪明,可以重用
BackgroundWorker
线程。由于工作线程等待所有任务完成,因此在同一线程中运行一个任务可能是一种优化

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

如果正在等待的任务 已开始执行,必须等待 块然而,如果它还没有开始 执行时,等待可能会拉动 将目标任务从计划程序中删除 并执行它 在当前线程上内联


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

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


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

但是OP提到工作程序显式地等待所有任务完成。@João:在等待的同时,其他任务可以使用您的线程。@Henk Holterman,我的怀疑与是否真的是其他任务或只是其中一个任务有关。这是优化在哪里的问题,如果它在TPL中,线程不会返回到池中,但是由于调用
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();