细说并发编程-TPL

windows为什么要支持线程

线程开销

CPU的发展

使用线程的理由

如何写一个简单Parallel.For循环

数据并行

Parallel.For剖析

  优秀软件的一个关键特征就是具有并发性。过去的几十年,我们可以进行并发编程,但是
难度很大。以前,并发性软件的编写、调试和维护都很难,这导致很多开发人员为图省事
放弃了并发编程。新版 .NET 中的程序库和语言特征,已经让并发编程变得简单多了。随
着 Visual Studio 2012 的发布,微软明显降低了并发编程的门槛。以前只有专家才能做并发
编程,而今天,每一个开发人员都能够(而且应该)接受并发编程。

  许多个人电脑和工作站都有多核CPU,可以同时执行多个线程。为了充分利用硬件,您可以将代码并行化,以便跨多个处理器分发工作。

  在过去,并行需要对线程和锁进行低级操作。Visual Studio和.NET框架通过提供运行时、类库类型和诊断工具来增强对并行编程的支持。这些特性是在.NET Framework 4中引入的,它们使得并行编程变得简单。您可以用自然的习惯用法编写高效、细粒度和可伸缩的并行代码,而无需直接处理线程或线程池。

  下图展示了.NET框架中并行编程体系结构。

使用场景

1 基本概念 1.1 并发编程

并发

同时做多件事情

  这个解释直接表明了并发的作用。终端用户程序利用并发功能,在输入数据库的同时响应用户输入。服务器应用利用并发,在处理第一个请求的同时响应第二个请求。只要你希望程序同时做多件事情,你就需要并发。

多线程

并发的一种形式,它采用多个线程来执行程序。从字面上看,多线程就是使用多个线程。多线程是并发的一种形式,但不是唯一的形式。

并行处理

把正在执行的大量的任务分割成小块,分配给多个同时运行的线程。

  为了让处理器的利用效率最大化,并行处理(或并行编程)采用多线程。当现代多核 CPU行大量任务时,若只用一个核执行所有任务,而其他核保持空闲,这显然是不合理的。

  并行处理把任务分割成小块并分配给多个线程,让它们在不同的核上独立运行。并行处理是多线程的一种,而多线程是并发的一种。

异步编程

并发的一种形式,它采用 future 模式或回调(callback)机制,以避免产生不必要的线程。

  一个 future(或 promise)类型代表一些即将完成的操作。在 .NET 中,新版 future 类型
有 Task 和 Task 。在老式异步编程 API 中,采用回调或事件(event),而不是
future。异步编程的核心理念是异步操作:启动了的操作将会在一段时间后完成。这个操作
正在执行时,不会阻塞原来的线程。启动了这个操作的线程,可以继续执行其他任务。当
操作完成时,会通知它的future,或者调用回调函数,以便让程序知道操作已经结束。

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本身,所以用户的计算体验变得更好了。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjzxd.html