问题
AFAIK some methods in the .Net library are able to do I/O jobs asynchronously without consuming a thread from the pool.
If my information are correct the WebClient *Async methods do that.
I'd like to verify it by checking that effectively threads from the pool are not used during a download.
So my general question is : how can I monitor the current state of the thread-pool?
number of threads
number of busy threads
Is there some API (GetAvailableThreads?) or performance counters that would give this information?
EDIT: here are some more details
I'm writing a simple benchmark for educational purposes:
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);
I'm comparing :
- naive sequential loop
- PLINQ loop
- async I/Os
The interesting part are the last two.
I expect and try to prove that async I/Os are:
faster because they will create less pressure on the pool (less threads need to be created...)
lighter because they will consume less thread of the pool
My "benchmark" shows that it's faster and I guess that's because the pool does not need to allocate new threads for each request whereas with PLINQ each parallel request will block one thread.
Now I'd like to check the numbers about thread consumption.
The commented task was a poor attempt to monitor the pool. It may be the good starting point but until now the result are not really consistent with what I expect: it never displays that more than 3/4 threads are consumed, whereas I expect something like 32 threads busy.
I'm open to any idea to enhance it or better any other use-case that would clearly highlight the differences between the two approaches.
Hope this is clearer now, and sorry for not having provided the details sooner. :)
回答1:
The ThreadPool class provides the GetAvailableThreads method which "Retrieves the difference between the maximum number of thread pool threads returned by the GetMaxThreads method, and the number currently active." [1]: http://msdn.microsoft.com/en-us/library/system.threading.threadpool.getavailablethreads%28v=vs.110%29.aspx
You can capture the ratio thustly:
int workerThreads;
int completionPortThreads;
ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
Console.WriteLine("{0} of {1} threads available", workerThreads, completionPortThreads);
来源:https://stackoverflow.com/questions/20109849/how-to-track-net-thread-pool-usage