浅谈.NET下的多线程和并行计算(十二)CLR via C#第三版阅读笔记(1)

最近此书出了第三版,在阅读此书线程部分的过程中有很多心得,补充了此前知识盲点,因此把这些 关键和重要的知识点汇集成日志文章并且纳入到这个系列中。顺便说一下,笔者喜欢这本书的原因是作者 作为微软顾问并没有按照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。

时间: 2025-01-01 11:22:55

浅谈.NET下的多线程和并行计算(十二)CLR via C#第三版阅读笔记(1)的相关文章

浅谈.NET下的多线程和并行计算(二)线程基本知识

首先来看看如何创建线程: Console.WriteLine(Process.GetCurrentProcess().Threads.Count); Thread t1 = new Thread(() => { Thread.Sleep(1000); Thread t = Thread.CurrentThread; Console.WriteLine("Name: " + t.Name); Console.WriteLine("ManagedThreadId: &quo

浅谈.NET下的多线程和并行计算(一)前言

作为一个ASP.NET开发人员,在之前的开发经历中接触多线程编程的机会并不是很多,但是随着.NET 4.0的发布临近,我越来越感受到未来的1-2年中并行计算将会有很大的应用.于是决定通过写日志的方式 来总结一下.NET 3.5下的多线程编程进而引入.NET 4.0提供的新的并行库以及新的并行编程模式和编程的 思维方式. 个人觉得在日常的编程中对于ASP.NET程序员来说使用多线程编程不是很多,其实我们无时无刻不在享 受多线程的优势.首先,WEB服务器环境就是一个多线程环境,每一个请求都是独立的线

浅谈.NET下的多线程和并行计算(九)Winform中多线程编程基础 下

在之前的文章中我们介绍过两种Timer和BackgroundWorker组件,在上文中我们提到过,强烈建议在UI 线程上操作控件,否则很容易产生人品问题.可以想到,上次介绍的两个Timer基于ThreadPool,回调方 法运行于不同于UI线程的新线程上,在这个方法中操作控件需要进行 Invoke或BeginInvoke.其实,还有 第三种System.Windows.Forms.Timer,它可以让回调事件在UI线程上执行,我们来做一个实验比较一下 System.Windows.Forms.T

浅谈.NET下的多线程和并行计算(四)线程同步基础 下

回顾一下上次,我们讨论了lock/AutoResetEvent/ManualResetEvent以及Semaphore.这些用于线程同 步的结构叫做同步基元.同步基元从类型上可以分为锁定/通知/联锁三种.lock显然锁定方式,而且是独 占锁定,也就是在锁释放之前不能由其它线程获得. Semaphore也是一种锁定,只不过不是独占锁,可以 指定多少个线程访问代码块.AutoResetEvent和ManualResetEvent当然就是通知方式了,前者在通行之后 自动重置,后者需要手动重置.我们还看

浅谈.NET下的多线程和并行计算(十四)并行计算前言

之前的文章中我们介绍了如何在.NET下运用相关类库进行多线程编程的基础,我们知道.NET 4.0已经 正式推出了,带来的重要特性是并行库.本文就谈谈对并行计算的一些理解和看法.并行计算不是一个很 新的概念,其实它就是通过多线程把同一个任务分割成多个子任务并行的执行的过程..NET 4.0并行库不 但提供了这方面的支持,而且还封装了多线程开发的各种场景,使得我们不需要依赖Thread/同步基元等 "底层"的对象就可以进行多线程开发.没有.NET 4.0的并行计算库我们同样可以进行并行计算

浅谈.NET下的多线程和并行计算(十).NET异步编程模型基础 上

谈多线程谈到现在,我们要明确多线程的一个好处是可以进行并行的运算(充分利用多核处理器,对 于桌面应用程序来说就更重要一点了,没有WEB服务器,利用多核只能靠自己),还有一个好处就是异步 操作,就是我们可以让某个长时间的操作独立运行,不妨碍主线程继续进行一些计算,然后异步的去返回 结果(也可以不返回).前者能提高性能是因为能利用到多核,而后者能提高性能是因为能让CPU不在等 待中白白浪费,其实异步从广义上来说也可以理解为某种并行的运算.在之前的这么多例子中,我们大多 采用手工方式来新开线程,之前也

浅谈.NET下的多线程和并行计算(十三)CLR via C#第三版阅读笔记(2)

线程同步的问题 1) 我们必须找到代码中所有可能被多个线程同时访问的资源,然后使用线程同步来保护资源,并且 我们没有办法来验证是不是正确进行了线程同步,包括是否有遗漏和是否对不需要同步的资源进行同步. 2) 线程同步是有损性能的,如果某个操作大量执行,并且这个操作原先的执行时间非常短,那么如 果我们对这段操作前后进行锁的申请和释放的话性能可能下降一个数量级. 3) 线程同步可能导致更频繁的线程创建和上下文的切换. 当然,只有在下面的情况下才需要线程同步,换句话说我们尽量不要使用下面的方案来导致线

浅谈.NET下的多线程和并行计算(十一).NET异步编程模型基础 下

上次我们说了,要进行多线程编程,我们可以使用最原始的方式也是最灵活的方式进行,那就是 Thread(ThreadPool)+信号量+ 锁+Control.Invoke..NET的异步编程模型给我们提供了一种基于 IAsyncResult的编程模式,它尤其适用于处理下面的应用场景: 1) 被阻止,正在等待一个 IAsyncResult 2) 被阻止,正在等待多个 IAsyncResult 对象 3) 轮询 IAsyncResult 上的完成情形 .NET还提供了基于事件的异步编程模式,它能够提供:

浅谈.NET下的多线程和并行计算(八)Winform中多线程编程基础 上

首先我们创建一个Winform的应用程序,在上面添加一个多行文本框和一个按钮控件,按钮的事件如下 : Thread.Sleep(1000); StringBuilder sb = new StringBuilder(); for (int i = 0; i < 10000; i++) sb.Append("test"); string s = sb.ToString(); textBox1.Text = s; 首先我们可以把这个操作理解为一个非常耗时的操作,它至少占用1秒的时间.