读书感受 - 软件工程师 - C#线程参考手册(多线程技术分析)

      这几天,花了些时间,浏览了下《C#线程参考手册》,对初学者比较有用。。。

      该书可以在我CSDN下载频道获得,请购买原书支持正版(http://lzhdim.download.csdn.net/)。

      几年前买过一本Intel的工程师写的《多核程序设计技术》一书,本来想开个专题来对多核程序的设计做介绍的,由于时间问题,该专题改为“并行程序设计”了,但该书的重要内容却没有记录下来,比较遗憾,后续有时间再补吧。(现在叫并行程序的比较多)

      其实Intel组织开展过多次并行程序的活动和编程专题,一来推广它的多核CPU,二来对推进并行程序的设计开发做铺垫,毕竟它和微软也是老伙伴了,向来不是我的软件推动你的硬件的发展,要不就是我的硬件更多的系列来支持你的软件更新换代。

      其实对于CPU的多核的发展,我觉得是挺慢的。早在多年前,DSP的硬件就已经支持并行处理了,而且有不少的芯片系列,开发板之类的,对于那些应用早就如火如荼的开展了(当时CPU还是单核的,服务器要装几个CPU,即主板上有几个CPU插槽)。而电脑CPU的发展比较缓慢,一个是由于硬件工艺技术上的发展限制(其实也挺快了,Intel一直都是用摩尔定律来进行硬件的升级发展),主要是nm级的火拼吧;一个也是价格上的问题,毕竟新工艺在实验室里研究成功后,还需要一定的时间才能投入到生产中;一个也是前面的CPU系列的更新换代问题,厂商们需要时间来推广和销售他们对应的电脑产品,比如主板,内存之类(产品线的更新是个大问题);还有一个重要的,就是操作系统的支持。操作系统需要根据新的硬件升级,更好的发挥出硬件的能力,更多的榨取硬件的价值。操作系统的价值不仅仅在于配合硬件,更好的提供客户的体验才是最主要的。(现在GPU的发展倒是挺快,抢了CPU的风头。CPU最初的应用就是计算,结果现在倒是大幅度的应用GPU的计算能力,真是对CPU的讽刺。)

      墨迹了这么多,转入正题吧。。。

      一、说到线程,从硬件CPU开始。早期的CPU技术,单核的,比如超线程技术,它的实质是在逻辑上(不是物理)映射另一个CPU核心,然后共享CPU的缓存,以软件的分配调度方式来模拟多核的应用(硬件底层是需要底层的软件代码来支持,即芯片内部的数据处理代码,其上才是操作系统,而操作系统需要再通过设备驱动程序才能访问该硬件)。这种支持超线程的CPU,在windows任务管理器中,能够看到2个至多个CPU使用记录的显示,但其实质上仍是1/2个硬核(现在的CPU,比如4核,如果支持超线程技术,那么显示为8个CPU记录,其它类推)。Intel刚开始推出超线程CPU技术,貌似挺好,但是早期的硬件设计、驱动以及操作系统的支持问题,Intel曾一度停止该超线程技术的应用。但是到了后来,因为技术成熟了,所以又开始应用该技术到CPU里。还是实际的硬核才是真道理。

           CPU不知道什么线程,它只负责处理数据。早期的总线型技术,能够提供的带宽相对比较小,随着硬件的发展,已经限制了CPU处理数据的速度,于是,最新的QPI型技术出来了,带宽增大了,当然,目前只在X58、P55之类的主板上才支持,新技术开始总是贵的。对于CPU来说,它只知道二进制指令(RISC指令集和CISC指令集)和二进制数据,而数据的长度(位数),即32bit、64bit决定了CPU处理数据的大小。芯片级代码的算法,就已经控制和调度哪个空闲的CPU核来处理并行的数据。所以,操作系统只需要调用硬件CPU厂商提供的驱动程序,并控制线程队列的运作即可,实质上做的是中介的应用。

      二、这里描述下线程的调度顺序。 用户应用程序 -> 操作系统 -> HAL -> 驱动程序 -> 主板北桥芯片组(P55只有南桥) -> 主板总线 -> CPU核心调度算法 -> CPU指令集 -> CPU缓存 -> CPU核心 。(这个顺序是我对硬件的理解,如果大家有不同的意见,欢迎批评指正)。

           我们用C#编写的并行程序,受CLR托管,而并行程序中的线程,受操作系统的管理。.NET框架已经提供了对线程的调用的方法集,考虑了线程的创建,更新,通信,同步,数据锁,异步通信等等问题。所以,除非特别需要,尽量使用框架提供的方法来操作线程,以取得更好的性能和效率以及控制力。

           1、理解线程的生命期。

           主要是对线程的状态变化进行理解,对于后面理解线程的运行机制和使用代码控制线程提供基础。

          

           上图介绍了C#中线程的操作方法和状态。应该对该图有个印象,后面应用这些方法就简单了。

           2、理解线程所处的环境。

           要使用C#提供的线程操作功能,必须先搞清楚线程所处的运行环境。下图展示了基本环境。

          

            上图是一个简要的环境描述。其中,CLR运行于操作系统上,而托管的应用程序进程,则运行在CLR的控制下。应用程序域对应于程序集。每个域里面,可能没有线程,也可能会有多个线程。

            3、调用线程。

            C#中调用线程很简单。Thread t=new Thread(new ThreadStart(Function)); t.Start();即可。这里线程的回收,也是由GC处理。

            线程的优先级也同样比较重要,当然也不能随意设置,太多的高优先级的线程将抢占CPU资源,反而会导致操作系统性能下降。线程的同步和线程安全是需要特别注意的地方。如果处理不好,则会导致资源竞争,导致死锁等问题。

            线程的同步,.NET框架中提供了几个操作类进行处理和控制。这个需要对各个操作类的应用深入了解,选择性的进行使用,以提供应用程序性能。

            比如,对共享资源的锁定及重要代码段的锁定,一般习惯性的用下列代码来实现:

代码

1 lock( object )
2 {
3     //do something 
4     //deal with object
5 }

             这个是常用的方式,在IL中生成的代码,与使用下面的代码类似,在IL上没啥区别。

代码

1 Monitor.Enter( object );
2 //do something 
3 //deal with object 
4 Monitor.Exit();

             这里有个小问题,Monitor.Enter( object );该方法会在资源object争用时导致线程等待(从而就会有死锁的可能发生),所以适合于该线程处理的内容为需要等待处理结束的应用。而如果是线程对线程的调度,或者线程监控某个资源的应用下,就得使用bool b=Monitor.TryEnter( object );该方法如果获取不到资源,则b将为false,这样下面就可以根据b来做分支判断是否执行处理数据代码了,否则可以结束该线程,等待下一个新线程对该资源的访问,从而不用等待资源的释放。选择哪个应用取决于实际环境的分析和设计了。

             4、线程池技术。

             线程池技术在多线程程序的效率上节省了创建新线程的时间,转为对线程资源的调度应用上。当然,线程池也不是万能的。它主要是应用在短暂的线程运行处理上,而不适用于某个处理大且长的应用上。对于线程池的应用,直接使用.NET框架中的ThreadPool操作类即可,其内置的处理方法与操作系统的配合,是一种高效的应用线程池的方案。

             如果在特殊场合,需要自己建立线程池的话(或者存储其它与线程类似的对象的对象池),建议尽量使用HashSet<T>泛型类来进行处理,而不要使用数组的方式来进行存储。该书中就是使用了ArrayList数组来进行处理。线程池一般都固定大小,所以会使用数组来进行处理。但是ArrayList也是长度可变的数组。在对存储的内容的处理上,数组也是存储在托管堆上的,但是它的区域是连续的内存区域,这个是它的特点,也是优点。而HashSet使用的是Hash的方式进行的存储,对于存储内容的处理上,对于增减内容的操作,对比固定数组的处理上要高效,因为数组如果删除中间的某个内容,需要循环以将后续的内容来填充至该删除的区域,可能降低了效率。在此不多说了,大家可以写些DEMO来做性能判断。

            1、我举个例子。线程池就象是工厂里面的多条生产线。需要生产产品的时候,我就取一条空闲的生产线来进行处理。生产达到任务后就让这条生产线空出来,等待 下一个生产调用。如果没有空闲的生产线,那么我会让该任务等待一下再去处理,或者增加一条生产线来处理任务,实在不行,再根据任务优先级来暂停某条生产 线,优先处理现在需要处理的任务。。。
           2、对于线程池中的线程,使用完后不是释放它的资源,而是让它空闲出来。是我这个“增减”没有描述清楚,是一个实现方式的问题,才导致了你的误会,下面说一下。
           3、那么,线程池怎么实现呢?
           如果使用一个固定长度的数组来实现的话,那么,就需要循环遍历数组来查找空闲可用的线程,在多个请求空闲线程的时候,还需要锁定该线程资源来保证线程安全等等。。。这个是一个实现方式。
          另 一个实现方式,就如书中所描述的。使用一个数组来存储已在使用线程,使用另一个数组来存储空闲的线程。请求空闲线程,直接从空闲数组中获取线程,并保存到 已使用数组中。已使用数组中的线程,完成任务后就保存到空闲数组中。这个就是我所说的线程“增减”的问题。。。这个是另一个实现方式。
至于这两种方式,效率和性能的取舍就要看大家怎么应用了。 

            5、多线程程序的调试

            VS中提供了工具,用来对多线程程序的调试提供了便利。具体请看该书的第6章。

 

            上述是说了几点,还是没有将概念讲透,请大家仔细阅读该书。

            下面给出些小参考:

            1、对于CPU硬件来说,主要的在与其运行的频率高低,决定了它的运行速度。所以,对于一个单核频率为3.0G的CPU,和一个双核2.0G的CPU,在使用单线程的应用程序,或者少量的多线程应用程序来说,由于3.0G的运行速度,那么其将比2.0G的双核CPU运行得快。而如果多线程的应用程序环境下,2.0G双核的CPU不定会比单核3.0G运行得快,这个主要是多线程程序会导致CPU频繁的切换线程,所以,不能片面的说多核的CPU就比单核的CPU速度快。对于目前最新的Core i5的四核CPU,比如2.0G频率,在硬件上已经做了优化,如果运行的主要是单线程的程序,那么它会把运行频率提高到3.0或者其它的频率,同时关闭其它的硬核,以提高运行速度。而在主要运行多线程的程序时,它会根据算法平均分配CPU资源以加快程序运行的效率。。。

            2、对于多线程程序的编写,一定要尽量少而精简的利用线程,以减少CPU对线程的调度切换的时间和效率。

            3、除了使用.NET框架提供的线程操作处理类方法外,还有其它第3方的解决方案,比如Intel就提供了第3方的组件来提供支持,这个可以参考《多核程序设计技术》一书。

            4、ASP.NET程序的运行,本身就是多线程的,所以,如果可以,建议查阅该方面底层的内容,对.NET框架如何应用多线程技术,以及如何提高效率做参考。

            5、可以查阅其它相关C#线程操作方面的书籍。或者找些C#写的网游游戏代码来做参考。这些都是多线程技术的典型应用方向。

 

            时间过得真快,转眼又到周末了,祝大家周末愉快吧。该休息的休息,该玩的玩。。。。。。

时间: 2024-10-29 03:38:14

读书感受 - 软件工程师 - C#线程参考手册(多线程技术分析)的相关文章

读书感受 - 软件工程师 - C#规范3.0版

      这几天花了点时间也把<C#规范3.0版>过了一遍,还是浏览,现在时间对我来说挺重要,只能过过,所以牺牲了一些具体学习的内容,建议初学者详细的看每句话,吃透C#的语法.       这个系列的电子书资源可以在我的CSDN下载频道找到:http://download.csdn.net/source/1792062  .       规范3.0,其实只是在1.2版的基础上,加入了2.0的概念,以及3.0自己的一些新增的概念而已.没有象2.0版那样是一个独立的新增内容的介绍,这个是3.0的

求《C#线程参考手册》源码

问题描述 求<C#线程参考手册>源码谢谢1973753446@qq.com 解决方案 解决方案二:帮忙啊,官网上没有!!!!解决方案三:帮忙啊,官网上没有!!!!

软件工程师所需掌握的“终极技术”是什么?

最近,我在微博上看到@程序员邹欣老师发的一条微博 - "不少大学同学都有一个想法:先做几年技术,然后做管理:也有一些同学说:我技术不行,希望直接找到一个管理的工作,就像PM那样.请看 PM 需要什么样的能力:(链接略去)".在读这条微博的前一部分内容时,我的第一反应是:难道同学们以为做技术管理不需要很好的技术功底?刚好在此之前,我写过<技术敏感度 - 基层技术管理者必备>一文,强调技术功底对于基层技术管理者的重要性.于是,我对该条微博评论了:"建议邹老师建议他们好

读书感受 - 软件设计师 - 你必须知道的.NET (C#类型存储方式分析)

      这几天花了些时间,相对仔细的阅读了<你必须知道的.NET>这本书,因为没有多少时间,请大家在看该书的时候一定要理解内容,转变成自己的经验.下面仅做简单的书评.         该书详细的介绍了C#类型的存储分配问题,对于值类型和引用类型的存储和类型的转换,都用了大篇幅来进行说明,如果还想再详细些,就得去看.net framework中的底层方法和机制了.其实它的这个存储分配,不该说是C#,应该是.net这个框架的存储分配方式.对于其它语言,比如VB.NET,VC++.NET也是一致

解密十五大顶级公司软件工程师薪资

国外求职网站 Glassdoor 日前整理其薪酬信息数据库,从中列举出世界上 15 家最大科技公司支付给软件工程师的薪酬.结果非常有趣:软件工程师是一份收入不错的工作,无论你在哪里工作.但即使在科技界,软件工程师也不会收到高得离谱的薪水.此外,并非每家公司都向其软件工程师发放高额薪水. 通用电气:市值 2570 亿美元,软件工程师平均薪酬 80235 美元.员工满意度 3.6 分(总分 5 分),26% 的员工认为通用业务发展方向正确,并在未来 6 个月内有所改善.通用驻肯塔基州路易斯维尔软件工

MySQL中文参考手册2(MySQL 的一般信息)

mysql|参考|参考手册|中文 MySQL中文参考手册2(MySQL 的一般信息)转载 翻译:晏子 [返回][转发] 译者:晏子 (clyan@sohu.com)主页:http://linuxdb.yeah.net 1 MySQL 的一般信息这是MySQL参考手册:它记载了MySQL版本3.23.7-alpha. MySQL 是一个快速.多线程.多用户和强壮的SQL数据库服务器. 对Unix和 OS/2 平台,MySQL基本上是免费的:但对微软平台,你在30 天的试用期后必须获得一个MySQL

MySQL中文参考手册5(安装MySQL下)

mysql|参考|参考手册|中文 MySQL中文参考手册5(安装MySQL下)转载 译者:晏子 [返回][转发] 译者:晏子 (clyan@sohu.com)主页:http://linuxdb.yeah.net 4.12 Win32 注意事项这节描述在Win32上安装和使用MySQL,这也在MySQL Win32分发所带的"readme"文件中描述.  4.12.1 在Win32上安装MySQL如果你没有一个注册的MySQL版本,你应该首先下载共享软件版本,从:  MySQL 3.21

MySQL中文参考手册5(安装MySQL上)

mysql|参考|参考手册|中文 MySQL中文参考手册5(安装MySQL上)转载 译者:晏子 [返回][转发] 译者:晏子 (clyan@sohu.com)主页:http://linuxdb.yeah.net4 安装MySQL本章描述怎样获得并安装MySQL:  对于你能从其获得MySQL的站点列表,见4.1 怎样获得MySQL. 要了解支持哪些平台,见4.2 MySQL支持的操作系统. 可获得MySQL的多个版本,以二进制代码和源代码形式分发.为了确定你应该使用的分发的版本和类型,见4.4 

[JAVA软件工程师-面试宝典-2013最新版]

[JAVA面试宝典-2013最新版] 一. Java基础部分......................................................................................................2 1.一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制?.....2 2.Java有没有goto?....................................................