多线程基础知识(二)
线程池
- 因为每次创建线程、销毁线程都比较消耗 cpu 资源,因此可以通过线程池进行优化。线程池是一组已经创建好的线程,随用随取,用完了不是销毁线程,然后放到线程池中,供其他人用。
- 用线程池之后就无法对线程进行精细化的控制了(线程启停、优先级控制等)。
- ThreadPool 类的一个重要方法:
- static bool QueueUserWorkItem(WaitCallback callBack)
- static bool QueueUserWorkItem(WaitCallback callBack, object state)//用来传递一个参数给线程代码的
- 除非要对线程进行精细化的控制,否则建议使用线程池,因为又简单、性能调优又更好。
1 static void Main(string[] args) 2 { 3 ThreadPool.QueueUserWorkItem(state => 4 { 5 for (int i = 0; i < 50; i++) 6 { 7 Console.WriteLine(i); 8 } 9 }); 10 }
1 static void Main(string[] args) 2 { 3 4 for (int i = 0; i < 50; i++) 5 { 6 //通过第二个参数给线程传值 7 ThreadPool.QueueUserWorkItem(state => 8 { 9 Console.WriteLine(state); 10 }, i); 11 } 12 Console.Read(); 13 }
三种异步编程模型
.Net 中很多的类接口设计的时候都考虑了多线程问题,简化了多线程程序的开发。不用自己去写 WaitHandler 等这些底层的代码。由于历史的发展,这些类的接口设计有着三种不同的风格:EAP(*)、APM(*)和 TPL。
目前重点用 TPL。
1.EAP风格:类似于 Ajax 中的XmlHttpRequest,send 之后并不是处理完成了,而是在 onreadystatechange 事件中再通知处理完成
1 WebClient wc = new WebClient(); 2 wc.DownloadStringCompleted += Wc_DownloadStringCompleted; 3 wc.DownloadStringAsync(new Uri("http://www.baidu.com")); 4 private void Wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) 5 { 6 MessageBox.Show(e.Result); 7 }
优点是简单,缺点是当实现复杂的业务的时候很麻烦;EAP 的类的特点是:一个异步方法配一个***Completed 事件。.Net 中基于 EAP 的类比较少
2.APM风格:是.Net 旧版本中广泛使用的异步编程模型。使用了 APM的异步方法会返回一个 IAsyncResult 对象,这个对象有一个重要的属性 AsyncWaitHandle,他是一个用来等待异步任务执行结束的一个同步信号。
APM 的特点是:方法名字以 BeginXXX 开头,返回类型为 IAsyncResult,调用结束后需要EndXXX。.Net 中有如下的常用类支持 APM:Stream、SqlCommand、Socket 等。
TPL风格:是.Net4.0后带来的新特性,更简洁、方便、现在.NET平台已经大面积使用
注意方法中如果有 await,则方法必须标记为 async,不是所有方法都可以被轻松的标记为 async。
WinForm 中的事件处理方法都可以标记为 async、MVC 中的 Action 方法也可以标记为 async、
控制台的 Main 方法不能标记为 async。
TPL 的特点:方法都以 XXXAsync 结尾,返回值类型是泛型的 Task<T>。TPL 让我们可以用线性的方式去编写异步程序,不再需要像 EAP 中那样搞一堆回调、逻辑跳来跳去了。
注意TPL中返回值直接使用即可,尽量不要使用其它一些方法的解析,比如:Result()
编写自己的一个异步方法
以async结尾最好,编写习惯
static Task<string> F2Async(){ return Task.Run(()=>{ System.Thread.Sleep(2000) return "helloWord!"; }); }