线程总结


一、线程基础
(1)作用:为设计和实现可伸缩的,可响应和可靠的应用程序和组件,线程是必须的核心技术。
二、CLR线程池
(1)CLR线程池线程池的引入:
创建和销毁线程是一个昂贵的操作,需要大量的时间
太多的线程会浪费内存资源,线程的上下文切换还有损性能
(2)CLR线程池是什么
想像成线程的集合,线程池可以容纳少量线程,从而避免浪费资源,也可以容纳功能多的线程,以利用多处理器,超线程出来器和多核处理器。如果应用程序发出请求
的速度超过了线程池的处理速度,就会创建额外的线程。当一个线程池线程很闲,线程会自己醒来终止自己以释放资源。
(3)每个CLR一个线程池,这个线程池由CLR控制的所有AppDomain共享。如果一个进程加载多个CLR,每个CLR都有自己的线程池.
(4)线程池线程划分:
工作者线程:异步的计算限制操作
I/O线程:I/O限制的异步操作
(5)线程池如何管理线程(工作者线程和I/O线程)
将线程池看成一个黑盒,是一种常规用途的线程调度技术,强烈信任它。强烈建议不要调用限制线程池的线程数,一般只会造成应用程序的性能变得越差,而不会变得更好。

三、计算限制的异步操作
(一)概念:使用其他线程执行它
(二)举例:编译代码,拼写检查,语法检查,电子表格重计算,音频或视频数据转码以及生成图像的缩略图。金融行业和工程行业。
(三)计算限制的异步操作解决办法
(1)线程池ThredPool实现
(2)任务Task实现
线程池ThreadPool的QueueUserWorkItem方法发起一异步的,受计算机限制的操作室非常简单的。然而这个技术存在很多限制。最大的问难是没有一个内建的机制让你
知道操作什么时候完成,也没有一个机制在操作完成的时候获得一个返回值。为了克服这些限制。Microsoft引入了任务的概念
(3)执行定时的计算限制操作
System.Threading命名空间中一个Timer类.可用它让一个线程池定时调用一个方法。相当于告诉线程池在某一个时间(具体由你指定)回调你的方法。

四、I/O限制的异步操作

(二)异步方式执行I/O操作的好处

  一) 可以将线程数控制在少数几个

 (1)资源使用率的降低,并减少了上下问的切换,

(2)线程越少垃圾回收器运行得速度越快(因为每一次垃圾回收,CLR必须挂起进程中的所有线程)

(3)线程越少,栈的数量越少,垃圾回收器的素对变得越快。

(4)线程越少调试更容易(因为调试过程中,一旦遇到断点,会挂起调试程序中的所有线程,继续执行调试的应用程序,Windows必须恢复它的所有线程)

  二)如果执行多个异步I/O操作获得所有结果的时间是表现最差的那个操作所需时间(同步操作是所有操作时间之和)

  三)对于GUI应用程序:应用程序的用户界面不会挂起,会在最终用户面前一直保持可响应性(Silverlight没有提供同步的I/O操作,执行同步I/O操作的线程可能阻塞以等待Web服务器响应会导致整个浏览器冻结,用户不能切换到另一个标签页)

五、异步编程模型

    异步操作是构建高性能、可伸缩应用程序的关键,它允许用非常少的线程执行许多操作。和线程池配合,异步操作允许你利用机器中的所有CPU。

   异步模型允许多得多的并发客户端,允许使用少的少的资源,能够更快的处理客户端(因为减少了上文切换)提高了垃圾回收速度,并增强了调试性能。

一)CLR异步编程模型APM(Asynchronous Programming Model)
 1)概念及原理

       以BeginXxx调用结束,以一个EndXxx调用开始,在EndXxx和BeginXxx方法之间,只执行计算限制的操纵;I/O操作在这些方法的“边界”处执行,所以线程永远不会阻塞。在每个方法之后,线程都回到线程池中,以便在哪里处理传入的客户端请求或者传入的网络响应。如果线程很忙,它会自动创建多个线程处理工作负荷。服务器能根据工作负荷和机器中的CPU数而自动伸缩。    

2)举例说明

这种方式就是提供两个方法实现异步编程:比如System.IO.Stream的Read方法:
public int Read(byte[] buffer,int offset,int count);
它还提供了两个方法实现异步读取:
public IAsyncResult BeginRead(byte[] buffer, int offset,int count,AsyncCallback callback);
public int EndRead(IAsyncResult asyncResult);

其中callback具有AsyncCallBack委托类型

public delegate void AsyncCallback(IAsyncResult ar)

3)APM的缺点

  (1)必须将代码分解成多个回调方法  

   (2)与传统方法的调用方 式相比,异步调用时的中间数据不能存放在线程栈上,方法之间的也不能简单地通过参数传递的方式来共享数据。此外,传统方法调用中可使用的 try…catch…finally,using等关键字都无法跨越方法边界,因此异步编程在处理异常,保护资源等方面也需要花更大的精力才行。如果一不 小心,轻则造成资源泄露,重则使整个应用程序崩溃。

  (3)很难实现多个并发操作协作进行,取消和超时,以及将工作封送给GUI线程以更新控件 

    辅助类库让异步更简单Jeffrey Richter的AsyncEnumerator。允许使用同步编程模型来执行异步操作

4)APM和计算限制的操作

    (1)委托符合APM模型,用委托实现计算限制操作(异步回调实现)

    (2)原理:委托的BeginInvoke方法是在内部调用ThreadPool的QueueUserWorkItem将计算限制的操作添加到CLR的线程池队列中。最后BeginInvoke将IAsysncResult对象返回给它的调用者。

   (3)优缺点

          通过委托的BeginInvoke方法,任何方法都可以异步调用,但这样做的实时是在使用一个线程,所以效率会有一定损失。

/// <summary>
        /// 为了保证程序UI的可响应性,或者为了利用计算机中的其他CPU,希望异步执行Sum方法
        /// (一)委托符合APM模型,用委托实现计算限制操作(异步回调实现)
        /// Fun<T,TResut>委托
        /// public delegate TResult Func<T,TResult>(T arg);中包含了
        /// public IAsncResult BeginInvoke(T arg,AsyncCallback callback,Object object)
        /// public TResult EndInvoke(IAsyncResult result)
        /// 其实任何委托都包含了BeginInvoke,和EndInvoke这个是符合APM编程模型的
        /// 所以用委托实现计算限制的操作太简单了
        /// (二)原理
        ///  委托的BeginInvoke方法是在内部调用ThreadPool的QueueUserWorkItem将计算限制的操作添加到CLR的线程池队列中。
        ///  最后BeginInvoke将IAsysncResult对象返回给它的调用者。
        /// </summary>
        private static void APMSum()
        {    
            //初始化一个委托变量,让它引用想要的异步调用方法
            Func<UInt64, UInt64> sumDelegate=Sum;
            //使用一个线程池线程调用方法
            sumDelegate.BeginInvoke(1000000000,SumIsDone,sumDelegate);
            //在这里可以执行其他的代码
            //处于演示的目的我们将主线程挂起
            Console.WriteLine();
        }
        private static void SumIsDone(IAsyncResult ar)
        { 
            //从IAsyncResult对象中提取sumDelegate(state)
            var sumDelegate=(Func<UInt64,UInt64>) ar.AsyncState;
            try
            {
                //获取结果并显示它
                Console.WriteLine("Sum's result:" + sumDelegate.EndInvoke(ar));
            }
            catch(OverflowException)
            {
                Console.WriteLine("Sum's restult is too large to caculate");
            }
        }
        private static UInt64 Sum(UInt64 n)
        {
            UInt64 sum = 0;
            for (UInt64 i = 1; i <= n; i++)
            {
                checked 
                {
                    //在此使用checked代码,用一个UInt64装不下
                    //sum抛出一个OverflowException异常
                    sum += i;
                }
            }
            return sum;
        }

(4)APM的注意事项

(5)将IASyncResult转为Task
二)基于事件的编程模型EAP(Event-based Asynchronous Pattern)
(1)优点:它同Microsoft Visual Studio UI设计器进行了很好的集成
支持EAP的类自动将应用程序映射到他得线程处理模型
EAP类在内部使用SynchronizationContext类
提供了取消和进度报告功能
(2)FCL中有17个类型实现了EAP模型
列如:System.ComponetModel.Component的派生类:System.ComponetModel.BackgroundWorker System.Net.WebClient
System.Object的派生类:System.Net.Mail.SmtpClient
而这17类中只有BackgroundWorker类用于执行异步的计算限制的工作,如果用于I/O限制会阻塞一个线程。

(3)EAP执行I/O限制操作举例

  private void button4_Click(object sender, RoutedEventArgs e)
        {
            //System.Net.WebClient类支持基于事件的异步编程模型(EAP)
            WebClient wc = new WebClient();
            wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
            //开始异步操作(这个类似于调用一个BeginXxx方法)
            wc.DownloadStringAsync(new Uri("http://www.baidu.com"));
        }
        void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
               
            }
            else
            {
                MessageBox.Show(e.Result);
            }
        }

(4)EAP(BackgroundWorker类用于执行异步的计算限制的工作)

基于事件的异步模式

五、应用程序及其线程处理模型

(1)控制台应用程序和Windos服务

    没有引入任何种类的线程处理模型

(2)GUI应用程序(包括Windows窗体、WPF和Silverlight)

     引入了一个线程处理模型:创建窗口的线程是唯一能对那个窗口进行更新的线程。

     在GUI线程中经常需要生产一个异步操作,使GUI线程不至于阻塞并停止响应用户输入(鼠标、键盘事件).由于异步操作是一个线程池完成的,而线程池不能更新UI。因此线程池需要用某种方式让GUI线程更新UI.

      这种方式就是Invoke(WinForm),Dispatcher.Invoke(WPF)

       可以参看如下链接

        线程间操作无效: 从不是创建控件" XX" 的线程访问它

(3)Asp.Net Web窗体和XMl Web服务

     类似于控制台应用程序。允许线程做它爱做的任何事情

六、.net4.0新秀任务Task对I/O限制,计算限制通吃(线程池也有这个能力)

七、项目中碰到的问题

(1)定时调用WebService

(2)切换Tab页调用不同webservice(服务数据每一分钟有更新)将获取到到不同的数据显示到TabItem页面上(就是要每次切到Tab页上要重新调用webservice).过程中切换过快的问题。

   解决办法:1)在vs中生成同步的WebService服务,在调用时需要使用线程或者异步方式调用服务

                   2)在vs中生成异步的Webservice服务,在调用时需要在异步回调的方法中操作UI控件。也可以手动编写一部服务。将你服务实现写成2个方法(BeginXxx,EndXxx并加上[WebMethod]特性标记符。

(3)拖动滚动条分批加载数据呈现(需要用异步调用webservice)

八、代码下载

代码下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值