慎用.NET2.0 ThreadPool

在一般观念中,ThreadPool管理了一些预先初始化好的线程,ThreadPool接受任务后,多数情况下能省去了线程创建的开销,更快地开始执行。但.NET 2.0 ThreadPool的表现也许和您的期望有所差距。下面的程序专门测试ThreadPool从接受任务到开始执行的时间延迟:

 测试1:并发创建10个sleep 500ms的任务,对比ThreadPool启动时间延迟和创建新线程的时间延迟。注:ThreadPool最小空闲线程数设为10。

 1 static void Main(string[] args)
 2 {
 3     ThreadPool.SetMinThreads(101000);
 4 
 5     List<Stopwatch> watches = new List<Stopwatch>();
 6 
 7     for (int i = 0; i < 10; i++)
 8     {
 9         watches.Add(new Stopwatch());
10         watches[i].Start();
11 
12         ThreadPool.QueueUserWorkItem(delegate(object obj)
13         {
14             int id = (int)obj;
15 
16             watches[id].Stop();
17 
18             Console.WriteLine("Pool Thread {0}, start delay: {1}ms", id, watches[id].ElapsedMilliseconds);
19 
20             Thread.Sleep(500);
21         }, i);
22     }
23 
24     Thread.Sleep(5 * 1000);
25 
26     Console.WriteLine("Press Key to Continue Test ");
27 
28     Console.ReadLine();
29 
30     watches.Clear();
31     for (int i = 0; i < 10; i++)
32     {
33         watches.Add(new Stopwatch());
34 
35         watches[i].Start();
36 
37         Thread thread = new Thread(delegate(object obj)
38         {
39             int id = (int)obj;
40 
41             watches[id].Stop();
42 
43             Console.WriteLine("Create New Thread {0}, start delay: {1}ms", id, watches[id].ElapsedMilliseconds);
44 
45             Thread.Sleep(500);
46         });
47 
48         thread.Start(i);
49     }
50 
51 
52     Console.ReadLine();
53 }

 

结果1:

Pool Thread 0, start delay: 6ms
Pool Thread 2, start delay: 9ms
Pool Thread 1, start delay: 5ms
Pool Thread 3, start delay: 508ms
Pool Thread 4, start delay: 508ms
Pool Thread 5, start delay: 509ms
Pool Thread 6, start delay: 1005ms
Pool Thread 7, start delay: 1008ms
Pool Thread 8, start delay: 1008ms
Pool Thread 9, start delay: 1009ms

Press Key to Continue Test...

Create New Thread 0, start delay: 25ms

Create New Thread 1, start delay: 25ms
Create New Thread 2, start delay: 5ms
Create New Thread 3, start delay: 4ms
Create New Thread 4, start delay: 4ms
Create New Thread 5, start delay: 5ms
Create New Thread 6, start delay: 4ms
Create New Thread 7, start delay: 3ms
Create New Thread 8, start delay: 3ms
Create New Thread 9, start delay: 3ms

怎么样,是不是很让人惊讶,ThreadPool的任务启动延迟居然到了1000ms左右!?最少也是6ms,而新线程方式的任务启动延迟一般才5ms左右。另外,ThreadPool的SetMinThreads似乎不起作用,前面3个任务启动在几ms,我期望的是10个都应该启动很快。

测试2:  并发创建10个sleep 10ms的任务,对比ThreadPool启动时间延迟和创建新线程的时间延迟。注:ThreadPool最小空闲线程数设为10。

 1 static void Main(string[] args)
 2 {
 3     ThreadPool.SetMinThreads(101000);
 4 
 5     List<Stopwatch> watches = new List<Stopwatch>();
 6 
 7     for (int i = 0; i < 10; i++)
 8     {
 9         watches.Add(new Stopwatch());
10         watches[i].Start();
11 
12         ThreadPool.QueueUserWorkItem(delegate(object obj)
13         {
14             int id = (int)obj;
15 
16             watches[id].Stop();
17 
18             Console.WriteLine("Pool Thread {0}, start delay: {1}ms", id, watches[id].ElapsedMilliseconds);
19 
20             Thread.Sleep(10);
21         }, i);
22     }
23 
24     Thread.Sleep(5 * 1000);
25 
26     Console.WriteLine("Press Key to Continue Test ");
27 
28     Console.ReadLine();
29 
30     watches.Clear();
31     for (int i = 0; i < 10; i++)
32     {
33         watches.Add(new Stopwatch());
34 
35         watches[i].Start();
36 
37         Thread thread = new Thread(delegate(object obj)
38         {
39             int id = (int)obj;
40 
41             watches[id].Stop();
42 
43             Console.WriteLine("Create New Thread {0}, start delay: {1}ms", id, watches[id].ElapsedMilliseconds);
44 
45             Thread.Sleep(10);
46         });
47 
48         thread.Start(i);
49     }
50 
51 
52     Console.ReadLine();
53 }

 

结果2:

Pool Thread 0, start delay: 1ms
Pool Thread 2, start delay: 29ms
Pool Thread 3, start delay: 29ms
Pool Thread 1, start delay: 28ms
Pool Thread 4, start delay: 39ms
Pool Thread 5, start delay: 39ms
Pool Thread 6, start delay: 40ms
Pool Thread 7, start delay: 40ms
Pool Thread 8, start delay: 49ms
Pool Thread 9, start delay: 49ms
Press Key to Continue Test...

Create New Thread 0, start delay: 9ms
Create New Thread 1, start delay: 10ms
Create New Thread 2, start delay: 11ms
Create New Thread 3, start delay: 3ms
Create New Thread 4, start delay: 3ms
Create New Thread 5, start delay: 3ms
Create New Thread 6, start delay: 3ms
Create New Thread 8, start delay: 46ms
Create New Thread 7, start delay: 97ms

Create New Thread 9, start delay: 90ms

这次ThreadPool延迟没有那么大,看来延迟和任务执行时间也有关系,如果ThreadPool中有长任务,会影响到后来任务的启动延迟。

测试3:依次创建10个sleep 500ms的任务,对比ThreadPool启动时间延迟和创建新线程的时间延迟。注:ThreadPool最小空闲线程数设为10。

 1 static void Main(string[] args)
 2 {
 3     ThreadPool.SetMinThreads(101000);
 4 
 5     List<Stopwatch> watches = new List<Stopwatch>();
 6 
 7     for (int i = 0; i < 10; i++)
 8     {
 9         watches.Add(new Stopwatch());
10         watches[i].Start();
11 
12         ThreadPool.QueueUserWorkItem(delegate(object obj)
13         {
14             int id = (int)obj;
15 
16             watches[id].Stop();
17 
18             Console.WriteLine("Pool Thread {0}, start delay: {1}ms", id, watches[id].ElapsedMilliseconds);
19 
20             Thread.Sleep(500);
21         }, i);
22 
23         Thread.Sleep(500); //依次创建线程
24     }
25 
26     Thread.Sleep(5 * 1000);
27 
28     Console.WriteLine("Press Key to Continue Test ");
29 
30     Console.ReadLine();
31 
32     watches.Clear();
33     for (int i = 0; i < 10; i++)
34     {
35         watches.Add(new Stopwatch());
36 
37         watches[i].Start();
38 
39         Thread thread = new Thread(delegate(object obj)
40         {
41             int id = (int)obj;
42 
43             watches[id].Stop();
44 
45             Console.WriteLine("Create New Thread {0}, start delay: {1}ms", id, watches[id].ElapsedMilliseconds);
46 
47             Thread.Sleep(500);
48         });
49 
50         thread.Start(i);
51 
52         Thread.Sleep(500); //依次创建线程
53     }
54 
55 
56     Console.ReadLine();
57 }

 

结果2:

Pool Thread 0, start delay: 1ms
Pool Thread 1, start delay: 2ms
Pool Thread 2, start delay: 0ms
Pool Thread 3, start delay: 0ms
Pool Thread 4, start delay: 0ms
Pool Thread 5, start delay: 0ms
Pool Thread 6, start delay: 0ms
Pool Thread 7, start delay: 0ms
Pool Thread 8, start delay: 0ms
Pool Thread 9, start delay: 0ms
Press Key to Continue Test...

Create New Thread 0, start delay: 3ms
Create New Thread 1, start delay: 2ms
Create New Thread 2, start delay: 1ms
Create New Thread 3, start delay: 1ms
Create New Thread 4, start delay: 1ms
Create New Thread 5, start delay: 1ms
Create New Thread 6, start delay: 1ms
Create New Thread 7, start delay: 1ms
Create New Thread 8, start delay: 1ms

Create New Thread 9, start delay: 2ms

依次执行任务,这次ThreadPool表现良好,但也没有看出和创建新线程相比有多大优势。

结论:.NET2.0 ThreadPool的表现也许不符合大多数人对于ThreadPool的期望,慎用!

补充:后来从网上看到资料,确认是.NET2.0 ThreadPool的一个bug,请参考http://www.cnblogs.com/anhr/archive/2008/05/24/ThreadPool_BUG_in_DotNET_2_0_SP1.html,文章提供了一个work around,就是在调用ThreadPool.QueryWorkItem后马上调用Thread.Sleep(1),经过我的测试有效果。

posted on 2008-10-15 13:35  Todd Wei  阅读(4250)  评论(13)    收藏  举报