27

阅读Parallel.ForEach 不断产生新线程后,我仍然怀疑它是否是计算并发线程数的正确方法?

我看到的是该方法计算同时输入但未完成的迭代(循环)的数量Parallel.ForEach
它是传达正确数量的同时运行线程的并发线程数量的同义词吗?
我不是专家,但我可以想象:

  • 线程可以在其活动在某处交换以供以后继续时重复使用。
  • 理论上,用于循环活动的线程在循环完成后保留在线程池中,但不会重新用于另一个
  • 或者扭曲实验(线程计数)纯度的可能性是什么?

无论如何,如何直接计算.NET进程的运行线程数,最好是(C#)代码?

更新:

因此,如果遵循Jeppe Stig Nielsen 的回答并使用计数

directThreadsCount = Process.GetCurrentProcess().Threads.Count;

那么输出就是,在 Release (threadsCount == 7) 和 Debug (threadsCount == 15) 模式下都非常相似:

[Job 0 complete. 2 threads remaining but directThreadsCount == 7
[Job 1 complete. 1 threads remaining but directThreadsCount == 7
[Job 2 complete. 2 threads remaining but directThreadsCount == 7
[Job 4 complete. 2 threads remaining but directThreadsCount == 7
[Job 5 complete. 2 threads remaining but directThreadsCount == 7
[Job 3 complete. 2 threads remaining but directThreadsCount == 7
[Job 6 complete. 2 threads remaining but directThreadsCount == 7
[Job 9 complete. 2 threads remaining but directThreadsCount == 7
[Job 7 complete. 1 threads remaining but directThreadsCount == 7
[Job 8 complete. 0 threads remaining but directThreadsCount == 7
FINISHED

也就是说,线程的数量并没有减少,说明上面引用的方法是不正确的,而System.Diagnostics.ProcessThread给出"Class name is not valid at this point"

我的结论是否正确,为什么不能ProcessThread使用

C#控制台应用程序的使用代码:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Edit4Posting
{
public class Node
{

  public Node Previous { get; private set; }
  public Node(Node previous)
  {
    Previous = previous;
    }
  }
  public class Edit4Posting
  {

    public static void Main(string[] args)
    {
      int concurrentThreads = 0;
      int directThreadsCount = 0;
      int diagThreadCount = 0;

      var jobs = Enumerable.Range(0, 10);
      Parallel.ForEach(jobs, delegate(int jobNr)
      {
        int threadsRemaining = Interlocked.Increment(ref concurrentThreads);

        int heavyness = jobNr % 9;

        //Give the processor and the garbage collector something to do...
        List<Node> nodes = new List<Node>();
        Node current = null;
        //for (int y = 0; y < 1024 * 1024 * heavyness; y++)
        for (int y = 0; y < 1024 * 24 * heavyness; y++)
        {
          current = new Node(current);
          nodes.Add(current);
        }
        //*******************************
        //uncommenting next line gives: "Class name is not valid at this point"
        //diagThreadCount=System.Diagnostics.ProcessThread
        directThreadsCount = Process.GetCurrentProcess().Threads.Count;
        //*******************************
        threadsRemaining = Interlocked.Decrement(ref concurrentThreads);
        Console.WriteLine(
           "[Job {0} complete. {1} threads remaining but directThreadsCount == {2}",
            jobNr, threadsRemaining, directThreadsCount);
      });
      Console.WriteLine("FINISHED");
      Console.ReadLine();
    }
  }
}
4

2 回答 2

56

我认为有不同种类的线程。您正在运行的应用程序的操作系统线程数可以计算为:

int number = Process.GetCurrentProcess().Threads.Count;

它似乎计算System.Diagnostics.ProcessThread实例。也许您需要计算另一种线程,例如“托管线程”,所以我不确定我的答案是否是您所寻求的。

于 2013-03-13T09:40:55.157 回答
13

我不是专家,但我可以想象线程可以在其活动在某处交换时重复使用。

不——除了一些非常特殊的情况(你几乎可以肯定不需要担心),线程不会被重入使用。在当前迭代完成后,该线程将被重用于运行另一个迭代(或其他任务) ,但您的代码运行时不会要求它执行其他操作。

所以你目前的方法基本上是合理的。

无论如何,如何直接计算 .NET 中正在运行的线程数?

您可以查看 perfmon,它会为您绘制图表。(如果进程在你的控制之下,最简单的方法是启动进程但让它等待输入,然后打开 perfmon,从“进程”选项中添加一个计数器,选择“线程计数”作为要添加的计数器,并限制从下拉列表中将其添加到您感兴趣的流程。点击确定,然后让您的流程开始工作。)

编辑:回答更新:

也就是说,线程数并没有减少,说明上述方法不正确

不,它所显示的只是积极运行代码的线程数量减少了,但线程仍然存在。这对于线程池来说是完全自然的。

为什么不能ProcessThread使用?

你只是不恰当地使用它。Jeppe 说系统正在计算 的实例,ProcessThread而您的代码尝试将类分配给变量:

diagThreadCount=System.Diagnostics.ProcessThread

那只是无效的代码。错误消息表明编译器意识到它是一个类型的名称,但您不能只为变量分配一个类型名称。

于 2013-03-13T09:22:15.753 回答