【问题标题】:Backgroundworker and TPL's Task have the same ManagedThreadID?Backgroundworker 和 TPL 的 Task 有相同的 ManagedThreadID?
【发布时间】:2010-09-17 12:02:32
【问题描述】:

我有一个 Backgroundworker,其目的是在后台按顺序运行作业。现在一项工作以多线程方式实现。这意味着,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。

【问题讨论】:

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


    【解决方案1】:

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

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

    如果正在等待的任务有 已经开始执行,等待必须 堵塞。但是,如果还没有开始 执行中,Wait 或许能拉 调度程序之外的目标任务 它被排队并执行它 在当前线程上内联。

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • 但是 OP 提到工作人员明确等待所有任务完成。
      • @João:在你等待的时候,其他东西可以使用你的线程。
      • @Henk Holterman,我的怀疑与真正成为其他东西或只是其中一项任务的可能性有关。这是优化在哪里的问题,如果它在 TPL 中,则线程不会返回到池中,而是由于对 Wait 的调用而内联了任务执行。基本上我只是不完全同意工作线程返回池的说法。
      【解决方案3】:

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

      当您创建任务时,它不会立即/永久地与线程关联。任务是放入队列中的作业,队列由工作线程提供服务。所以可能是 Bgw 任务被挂起,它的线程返回到池中,或者更直接地可以通过 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();  
      

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 2015-03-23
          • 2016-04-21
          • 1970-01-01
          • 2012-10-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-03-23
          • 1970-01-01
          相关资源
          最近更新 更多