tpl是什么( 二 )


NOTE:通常情况下,一个并发程序要使用多种技术 。大多数程序至少使用了多线程(通过线程池)和异步编程 。要大胆地把各种并发编程形式进行混合和匹配,在程序的各个部分使用 合适的工具 。
1.2 TPL
任务并行库(TPL)是System.Threading和System.Threading.Tasks命名空间中的一组公共类型和API 。
TPL动态地扩展并发度,以最有效地使用所有可用的处理器 。通过使用TPL,您可以最大限度地提高代码的性能,同时专注于您的代码的业务实现 。
从.NET Framework 4开始,TPL是编写多线程和并行代码的首选方式 。
2 线程基础
2.1 Windows 为什么要支持线程
在计算机的早期岁月,操作系统没提供线程的概念 。事实上,整个系统只运行着一个执行线程(单线程),其中同时包含操作系统代码和应用程序代码 。只用一个执行线程的问题在于,长时间运行的任务会阻止其他任务执行 。例如,在16位Windows的那些日子里,打印一个文档的应用程序很容易“冻结”整个机器,造成OS和其他应用程序停止响应 。有的程序含有bug,会造成死循环 。遇到这个问题,用户只好重启计算机 。用户对此深恶痛绝 。
于是微软下定决心设计一个新的OS,这个OS必须健壮,可靠,易于是伸缩以安全,同同时必须改进16位windows的许多不足 。
微软设计这个OS内核时,他们决定在一个进程(Process)中运行应用程序的每个实例 。进程不过是应用程序的一个实例要使用的资源的一个集合 。每个进程都被赋予一个虚拟地址空间,确保一个进程使用的代码和数据无法由另一个进程访问 。这就确保了应用程序实例的健壮性 。由于应用程序破坏不了其他应用程序或者OS本身,所以用户的计算体验变得更好了 。
听起来似乎不错,但CPU本身呢?如果一个应用程序进入无限循环,会发生什么呢?如果机器中只有一个CPU,它会执行无限循环,不能执行其它任何东西 。所以,虽然数据无法被破坏,而且更安全,但系统仍然可能停止响应 。微软要修复这个问题,他们拿出的方案就是线程 。作为Windows概念,线程的职责是对CPU进行虚拟化 。Windows为每个进程都提供了该进程专用的专用的线程(功能相当于一个CPU,可将线程理解成一个逻辑CPU) 。如果应用程序的代码进入无限循环,与那个代码关联的进程会被“冻结”,但其他进程(他们有自己的线程)不会冻结:他们会继续执行!
2.2 线程开销
线程是一个非常强悍的概念,因为他们使windows即使在执行长时间运行的任务时也能随时响应 。另外,线程允许用户使用一个应用程序(比如“任务管理器”)强制终止似乎冻结的一个应用程序(它也有可能正在执行一个长时间运行的任务) 。但是,和一切虚拟化机制一样,线程会产生空间(内存耗用)和时间(运行时的执行性能)上的开销 。
创建线程,让它进驻系统以及最后销毁它都需要空间和时间 。另外,还需要讨论一下上下文切换 。单CPU的计算机一次只能做一件事情 。所以,windows必须在系统中的所有线程(逻辑CPU)之间共享物理CPU 。
在任何给定的时刻,Windows只将一个线程分配给一个CPU 。那个线程允许运行一个时间片 。一旦时间片到期,Windows就上下文切换到另一个给线程 。每次上下文切换都要求Windows执行以下操作:
将CPU寄存器中的值保存到当前正在运行的线程的内核对象内部的一个上下文结构中 。从现有线程集合中选一个线程供调度(切换到的目标线程) 。如果该线程由另一个进程拥有,Window在开始执行任何代码或者接触任何数据之前,还必须切换CPU“看得见”的虚拟地址空间 。将所选上下文结构中的值加载到CPU的寄存器中 。上下文切换完成后,CPU执行所选的线程,直到它的时间片到期 。然后,会发生新一轮的上下文切换 。Windows大约每30ms执行一次上下文切换 。
上下文切换是净开销:也就是说上下文切换所产生的开销不会换来任何内存或性能上的收益 。
根据上述讨论,我们的结论是必须尽可能地避免使用线程,因为他们要耗用大量的内存,而且需要相当多的时间来创建,销毁和管理 。Windows在线程之间进行上下文切换,以及在发生垃圾回收的时候,也会浪费不少时间 。然而,根据上述讨论,我们还得出一个结论,那就是有时候必须使用线程,因为它们使Windows变得更健壮,反应更灵敏 。
应该指出的是,安装了多个CPU或者一个多核CPU)的计算机可以真正同时运行几个线程,这提升了应用程序的可伸缩性(在少量的时间里做更多工作的能力) 。Windows为每个CPU内核都分配一个线程,每个内核都自己执行到其他线程的上下文切换 。Windows确保单个线程不会在多个内核上同时被调度,因为这会代理巨大的混乱 。今天,许多计算机都包含了多个CPu,超线程CPU或者多核CPU 。但是,windows最初设计时,单CPU计算机才是主流,所以Windows设计了线程来增强系统的响应能力和可靠性 。今天,线程还被用于增强应用程序的可伸缩性,但在只有多CPU(或多核CPU)计算机上才有可能发生 。