CLR线程池的工作者线程

来源:互联网 发布:侠盗无双0.4下载 软件 编辑:程序博客网 时间:2024/05/20 21:59

关于CLR线程池

使用ThreadStart与ParameterizedThreadStart建立新线程非常简单,但通过此方法建立的线程难于管理,若建立过多的线程反而会影响系统的性能。
有见及此,.NET引入CLR线程池这个概念。CLR线程池并不会在CLR初始化的时候立刻建立线程,而是在应用程序要创建线程来执行任务时,线程池才初始化一个线程。线程的初始化与其他的线程一样。在完成任务以后,该线程不会自行销毁,而是以挂起的状态返回到线程池。直到应用程序再次向线程池发出请求时,线程池里挂起的线程就会再度激活执行任务。这样既节省了建立线程所造成的性能损耗,也可以让多个任务反复重用同一线程,从而在应用程序生存期内节约大量开销。

工作者线程与I/O线程

CLR线程池分为工作者线程(workerThreads)与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     }