【问题标题】:How to track .Net thread pool usage?如何跟踪 .Net 线程池的使用情况?
【发布时间】:2013-12-05 06:23:58
【问题描述】:

AFAIK .Net 库中的某些方法能够异步执行 I/O 作业,而无需消耗池中的线程

如果我的信息正确,WebClient *Async 方法会这样做。

我想通过检查池中的有效线程在下载期间没有被使用来验证它。

所以我的一般问题是:如何监控线程池的当前状态?

  • 线程数

  • 繁忙线程数

是否有一些 API (GetAvailableThreads?) 或 性能计数器 可以提供这些信息?


编辑:这里有更多细节

我正在为教育目的编写一个简单的基准测试:

string[] urls = Enumerable.Repeat("http://google.com", 32).ToArray();
/*{
    "http://google.com",
    "http://yahoo.com",
    "http://microsoft.com",
    "http://wikipedia.com",
    "http://cnn.com",
    "http://facebook.com",
    "http://youtube.com",
    "http://twitter.com"
};*/

/*Task.Run(() =>
    {
        while (true)
        {
            int wt, cpt;
            ThreadPool.GetAvailableThreads(out wt, out cpt);
            Console.WriteLine("{0} / {1}", wt, cpt);
            Thread.Sleep(100);
        }
    });*/

WebClient webClient = new WebClient();
Stopwatch stopwatch = Stopwatch.StartNew();
foreach (string url in urls)
{
    webClient.DownloadString(url);
    Console.WriteLine("Got '{0}'", url);
}
stopwatch.Stop();

TimeSpan sequentialTime = stopwatch.Elapsed;

stopwatch.Restart();
CountdownEvent cde = new CountdownEvent(1);
foreach (string url in urls)
{
    cde.AddCount();
    webClient = new WebClient();
    webClient.DownloadStringCompleted += (_, __) =>
    {
        Console.WriteLine("Got '{0}'", __.UserState);
        cde.Signal();
    };
    webClient.DownloadStringAsync(new Uri(url), url);
}
cde.Signal();
cde.Wait();
stopwatch.Stop();

TimeSpan asyncTime = stopwatch.Elapsed;

stopwatch.Restart();
ThreadLocal<WebClient> threadWebClient = new ThreadLocal<WebClient>(() => new WebClient());
urls.AsParallel().WithDegreeOfParallelism(urls.Length).ForAll(url => threadWebClient.Value.DownloadString(url));
stopwatch.Stop();

TimeSpan PLinqTime = stopwatch.Elapsed;

Console.WriteLine("Sequential time: {0}.", sequentialTime);
Console.WriteLine("PLinq time: {0}.", PLinqTime);
Console.WriteLine("Async time: {0}.", asyncTime);

我在比较:

  • 简单的顺序循环
  • PLINQ 循环
  • 异步 I/O

有趣的部分是最后两个。

我期望并尝试证明异步 I/O 是:

  • 更快,因为它们对池造成的压力更小(需要创建的线程更少...)

  • 更轻,因为它们会消耗更少的池线程

我的“基准”显示它更快,我猜这是因为池不需要为每个请求分配新线程,而使用 PLINQ 每个并行请求都会阻塞一个线程。

现在我想检查一下线程消耗的数字。

评论的任务是监控池的一次糟糕的尝试。这可能是一个很好的起点,但直到现在,结果与我的预期并不完全一致:它从未显示超过 3/4 的线程被消耗,而我预计会有 32 个线程忙。

我愿意接受任何可以增强它的想法或更好的任何其他可以清楚突出两种方法之间差异的用例。

希望现在更清楚了,很抱歉没有尽快提供详细信息。 :)

【问题讨论】:

  • @downvoters:如果您有任何不赞成投票的理由,请分享。如果你还没有走自己的路。谢谢。 :)
  • 是的,我也想知道为什么会有 2 票反对。如果不赞成投票者没有在 cmets 中给出理由,则它无助于 OP 纠正问题以满足不赞成投票者反对投票的理由。否则,OP 永远不会知道它是否只是出于热情。
  • 我觉得这个问题很好。我投了赞成票。 OP 有足够的代表让我们假设之前的一些研究是在没有解决方案的情况下完成的。
  • 我认为这是一个很好的问题。我正在尝试自己设置一些小样本以从线程池中学习。需要注意的是,maxconnection 限制了连接数。您可以从进程中的每个 AppDomain 创建最多两个到特定 IP 地址的连接。有关详细信息,请参阅support.microsoft.com/default.aspx/kb/821268
  • 您可以在 machine.config 中增加它。例如:。使用其他阻塞 IO 可能会更好,因为您可能会受到正在访问的服务器的限制。

标签: c# .net multithreading threadpool


【解决方案1】:

ThreadPool 类提供了 GetAvailableThreads 方法,该方法“检索由 GetMaxThreads 方法返回的线程池线程的最大数量与当前活动的数量之间的差异。” [1]:http://msdn.microsoft.com/en-us/library/system.threading.threadpool.getavailablethreads%28v=vs.110%29.aspx

你可以这样捕捉比率:

        int workerThreads;
        int completionPortThreads;
        ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
        Console.WriteLine("{0} of {1} threads available", workerThreads, completionPortThreads);

【讨论】:

  • 感谢您的回答woogy。这是我第一次尝试发现并使用的。但正如我在我的问题和 cmets 中所说的那样,我一定是在滥用它,因为结果不是我所期望的。我认为这是由于时间太短。我将尝试使用托管在 Apache 中的本地 PHP 脚本来模拟一个非常长的服务器,该脚本仅休眠 10 秒。这样,我的“基准”将更加可预测,并且能够更轻松地捕捉到我希望是我期望的行为。我会带着这个测试的结果回来。
  • @Pragmateek 有什么想法更好的方法吗?
  • @codebased 抱歉,如果我没记错的话,我还没有实现我的想法。也许从那时起,.Net 框架已经修复/增强/添加了一些 API 来完成这项工作......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多