关于CLR线程池
使用ThreadStart与ParameterizedThreadStart建立新线程非常简单,但通过此方法建立的线程难于管理,若建立过多的线程反而会影响系统的性能。
有见及此,.NET引入CLR线程池这个概念。CLR线程池并不会在CLR初始化的时候立刻建立线程,而是在应用程序要创建线程来执行任务时,线程池才初始化一个线程。线程的初始化与其他的线程一样。在完成任务以后,该线程不会自行销毁,而是以挂起的状态返回到线程池。直到应用程序再次向线程池发出请求时,线程池里挂起的线程就会再度激活执行任务。这样既节省了建立线程所造成的性能损耗,也可以让多个任务反复重用同一线程,从而在应用程序生存期内节约大量开销。
工作者线程与I/O线程
completionPortThreads) 两种,工作者线程是主要用作管理CLR内部对象的运作,I/O(Input/Output) 线程顾名思义是用于与外部系统交换信息
通过QueueUserWorkItem启动工作者线程
ThreadPool线程池中包含有两个静态方法可以直接启动工作者线程:
一为 ThreadPool.QueueUserWorkItem(WaitCallback)
二为 ThreadPool.QueueUserWorkItem(WaitCallback,Object)
先把WaitCallback委托指向一个带有Object参数的无返回值方法,再使用 ThreadPool.QueueUserWorkItem(WaitCallback) 就可以异步启动此方法,此时异步方法的参数被视为null 。
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 //把CLR线程池的最大值设置为1000
6 ThreadPool.SetMaxThreads(1000, 1000);
7 //显示主线程启动时线程池信息
8 ThreadMessage("Start");
9 //启动工作者线程
10 ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncCallback));
11 Console.ReadKey();
12 }
13
14 static void AsyncCallback(object state)
15 {
16 Thread.Sleep(200);
17 ThreadMessage("AsyncCallback");
18 Console.WriteLine("Async thread do work!");
19 }
20
21 //显示线程现状
22 static void ThreadMessage(string data)
23 {
24 string message = string.Format("{0}\n CurrentThreadId is {1}",
25 data, Thread.CurrentThread.ManagedThreadId);
26 Console.WriteLine(message);
27 }
28 }
使用 ThreadPool.QueueUserWorkItem(WaitCallback,Object) 方法可以把object对象作为参数传送到回调函数中。
下面例子中就是把一个string对象作为参数发送到回调函数当中。
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 //把线程池的最大值设置为1000
6 ThreadPool.SetMaxThreads(1000, 1000);
7
8 ThreadMessage("Start");
9 ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncCallback),"Hello Elva");
10 Console.ReadKey();
11 }
12
13 static void AsyncCallback(object state)
14 {
15 Thread.Sleep(200);
16 ThreadMessage("AsyncCallback");
17
18 string data = (string)state;
19 Console.WriteLine("Async thread do work!\n"+data);
20 }
21
22 //显示线程现状
23 static void ThreadMessage(string data)
24 {
25 string message = string.Format("{0}\n CurrentThreadId is {1}",
26 data, Thread.CurrentThread.ManagedThreadId);
27 Console.WriteLine(message);
28 }
29 }
通过ThreadPool.QueueUserWorkItem启动工作者线程虽然是方便,但WaitCallback委托指向的必须是一个带有Object参数的无返回值方法,这无疑是一种限制。若方法需要有返回值,或者带有多个参数,这将多费周折。有见及此,.NET提供了另一种方式去建立工作者线程,那就是委托。
回调函数
.NET为 IAsyncResult BeginInvoke(AsyncCallback , object)准备了一个回调函数。使用 AsyncCallback 就可以绑定一个方法作为回调函数,回调函数必须是带参数 IAsyncResult 且无返回值的方法: void AsycnCallbackMethod(IAsyncResult result) 。在BeginInvoke方法完成后,系统就会调用AsyncCallback所绑定的回调函数,最后回调函数中调用 XXX EndInvoke(IAsyncResult result) 就可以结束异步方法,它的返回值类型与委托的返回值一致。
1 class Program
2 {
3 delegate string MyDelegate(string name);
4
5 static void Main(string[] args)
6 {
7 ThreadMessage("Main Thread");
8
9 //建立委托
10 MyDelegate myDelegate = new MyDelegate(Hello);
11 //异步调用委托,获取计算结果
12 myDelegate.BeginInvoke("Leslie", new AsyncCallback(Completed), null);
13 //在启动异步线程后,主线程可以继续工作而不需要等待
14 for (int n = 0; n < 6; n++)
15 Console.WriteLine(" Main thread do work!");
16 Console.WriteLine("");
17
18 Console.ReadKey();
19 }
20
21 static string Hello(string name)
22 {
23 ThreadMessage("Async Thread");
24 Thread.Sleep(2000); \\模拟异步操作
25 return "\nHello " + name;
26 }
27
28 static void Completed(IAsyncResult result)
29 {
30 ThreadMessage("Async Completed");
31
32 //获取委托对象,调用EndInvoke方法获取运行结果
33 AsyncResult _result = (AsyncResult)result;
34 MyDelegate myDelegate = (MyDelegate)_result.AsyncDelegate;
35 string data = myDelegate.EndInvoke(_result);
36 Console.WriteLine(data);
37 }
38
39 static void ThreadMessage(string data)
40 {
41 string message = string.Format("{0}\n ThreadId is:{1}",
42 data, Thread.CurrentThread.ManagedThreadId);
43 Console.WriteLine(message);
44 }
45 }
如果想为回调函数传送一些外部信息,就可以利用BeginInvoke(AsyncCallback,object)的最后一个参数object,它允许外部向回调函数输入任何类型的参数。只需要在回调函数中利用 AsyncResult.AsyncState 就可以获取object对象。
1 class Program
2 {
3 public class Person
4 {
5 public string Name;
6 public int Age;
7 }
8
9 delegate string MyDelegate(string name);
10
11 static void Main(string[] args)
12 {
13 ThreadMessage("Main Thread");
14
15 //建立委托
16 MyDelegate myDelegate = new MyDelegate(Hello);
17
18 //建立Person对象
19 Person person = new Person();
20 person.Name = "Elva";
21 person.Age = 27;
22
23 //异步调用委托,输入参数对象person, 获取计算结果
24 myDelegate.BeginInvoke("Leslie", new AsyncCallback(Completed), person);
25
26 //在启动异步线程后,主线程可以继续工作而不需要等待
27 for (int n = 0; n < 6; n++)
28 Console.WriteLine(" Main thread do work!");
29 Console.WriteLine("");
30
31 Console.ReadKey();
32 }
33
34 static string Hello(string name)
35 {
36 ThreadMessage("Async Thread");
37 Thread.Sleep(2000);
38 return "\nHello " + name;
39 }
40
41 static void Completed(IAsyncResult result)
42 {
43 ThreadMessage("Async Completed");
44
45 //获取委托对象,调用EndInvoke方法获取运行结果
46 AsyncResult _result = (AsyncResult)result;
47 MyDelegate myDelegate = (MyDelegate)_result.AsyncDelegate;
48 string data = myDelegate.EndInvoke(_result);
49 //获取Person对象
50 Person person = (Person)result.AsyncState;
51 string message = person.Name + "'s age is " + person.Age.ToString();
52
53 Console.WriteLine(data+"\n"+message);
54 }
55
56 static void ThreadMessage(string data)
57 {
58 string message = string.Format("{0}\n ThreadId is:{1}",
59 data, Thread.CurrentThread.ManagedThreadId);
60 Console.WriteLine(message);
61 }
62 }