最近此书出了第三版,在阅读此书线程部分的过程中有很多心得,补充了此前知识盲点,因此把这些 关键和重要的知识点汇集成日志文章并且纳入到这个系列中。顺便说一下,笔者喜欢这本书的原因是作者 作为微软顾问并没有按照MSDN的教条教大家怎么去用而是能说出很多自己的观点甚至很多是微软.NET框架 不够的地方,并给出自己的实现。
为什么说线程是比较昂贵的?
1)从内存上来说,(对于32位架构)每一个线程包含线程内核对象(700字节)/线程环境块(4KB)/ 内核堆栈(12KB)/用户堆栈(1MB)。并且可以发现,这1MB的用户堆栈内存在CLR线程创建的时候完全分 配,并不是动态增加的(Windows线程的创建只是保留1MB的内存空间)。
2) 从线程切换上来说,需要做哪些步骤来进行切换?首先是把CPU寄存器中的值保存到当前线程的内 核对象中,然后如果线程切换到不同CPU的话需要为CPU准备新的虚拟地址空间,最后把目标线程内核对象 中寄存器的值复制到CPU寄存器中。
3) 更大的性能损害来自于,线程切换之后缓存中的数据可能会不能命中,需要重新准备这些数据。
4) 此外,在垃圾回收的时候,CLR会挂起所有线程,查看线程堆栈,垃圾回收压缩后重置堆栈指针地 址。
当然,线程总比进程的创建好一点,不过作者也说了线程多啊,一个OUTLOOK有几十个线程,作者还纳 闷怎么打开记事本的打开对话框会多22个线程,我想这个和操作系统有关,Vista的打开文件对话框更复 杂,在其中为了不阻塞UI很多Part都以新的线程来加载内容,还好这个打开对话框用的不是 CLR线程…… 当前CLR线程对应Windows线程,作者也希望在将来CLR能实现虚拟逻辑线程的概念,以改善性能。
什么时候手动创建线程而不是使用线程池?
1) 需要自定义线程的优先级,线程池的线程总是Normal。
2) 需要一个前台线程,线程池的线程总是后台线程。
作者建议大家对于非UI线程创建为后台线程而不是前台线程,有的时候我们可以发现有些软件在关闭 之后,或者说关闭UI之后在进程中还存在,占用内存,这是因为我们看到关闭的是UI线程,还有其它前台 线程未关闭。
3) 需要手动中止线程,线程池不提供这个功能。
4) 线程执行时间很长,线程池用于短而多的线程任务比较合适。
线程的调度
1) 每一个线程的优先级是0到31。高优先级的线程ready之后,不管低优先级的线程在做什么,立即 上位,没话说。Windows会把最高优先级的不同线程调度到各个CPU上并行执行,多核多处理器谁也不闲着 。
2) Windows制定进程有6个优先等级,线程有7个,通过组合来得出实际的线程优先级0到30(0优先级 保留给Windows用于内存释放)。CLR保留了线程优先级中的最低和最高级,供程序员可设置的只有5个等 级。
3)进程的优先级是一个虚拟的概念,只是为了帮助用于映射到1-31中的某个等级,一般来说进程的等 级默认为创建它的进程的等级。很多进程都是Windows Explorer创建的,默认也就是Nomral这个等级,说 白了我们的线程在大多情况下映射到Windows线程优先级为6-10。