.NET的并发编程(TPL编程)是什么? (上)

简介: .NET的并发编程(TPL编程)是什么?

写在前面

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

解答疑问:.NET Core 同步和异步的差别

public ActionResult PushFileData([FromBody] Web_PushFileData file) //同步

public async ActionResult PushFileData([FromBody] Web_PushFileData file) //异步

疑问:对于同步方法,每个请求都是使用同个线程吗?如客户A请求同步Action,还未执行完毕时,客户B请求会阻塞。

对于异步方法,每个请求都是从线程池拿空闲线程出来执行方法?也就是客户A和客户B请求方法,都是在不同子线程里分别执行的。

导航

基本概念

  • 并发编程
  • TPL

线程基础

  • windows为什么要支持线程
  • 线程开销
  • CPU的发展
  • 使用线程的理由

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

  • 数据并行
  • Parallel.For剖析

数据和任务并行中潜在的缺陷

  • 不要假设并行总是很快
  • 避免写入共享缓存
  • 避免调用非线程安全的方法

      许多个人电脑和工作站都有多核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本身,所以用户的计算体验变得更好了。

      听起来似乎不错,但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)计算机上才有可能发生。

TIP:一个时间片结束时,如果Windows决定再次调度同一个线程(而不是切换到另外给一个线程),那么Windows不会执行上下文切换。线程将继续执行,这显著改进了性能。设计自己的代码时注意,上下文切换能避免的就要尽量避免。

相关文章
|
5月前
|
存储 JSON 开发工具
Visual Studio编程效率提升技巧集(提高.NET编程效率)
Visual Studio编程效率提升技巧集(提高.NET编程效率)
Visual Studio编程效率提升技巧集(提高.NET编程效率)
|
2月前
|
传感器 数据采集 物联网
探索.NET nanoFramework:为嵌入式设备编程的新途径
探索.NET nanoFramework:为嵌入式设备编程的新途
51 7
|
4月前
|
大数据 开发工具 开发者
从零到英雄:.NET核心技术带你踏上编程之旅,构建首个应用,开启你的数字世界探险!
【8月更文挑战第28天】本文带领读者从零开始,使用强大的.NET平台搭建首个控制台应用。无论你是新手还是希望扩展技能的开发者,都能通过本文逐步掌握.NET的核心技术。从环境搭建到创建项目,再到编写和运行代码,详细步骤助你轻松上手。通过计算两数之和的小项目,你不仅能快速入门,还能为未来开发更复杂的应用奠定基础。希望本文为你的.NET学习之旅开启新篇章!
35 1
|
4月前
|
存储 C#
揭秘C#.Net编程秘宝:结构体类型Struct,让你的数据结构秒变高效战斗机,编程界的新星就是你!
【8月更文挑战第4天】在C#编程中,结构体(`struct`)是一种整合多种数据类型的复合数据类型。与类不同,结构体是值类型,意味着数据被直接复制而非引用。这使其适合表示小型、固定的数据结构如点坐标。结构体默认私有成员且不可变,除非明确指定。通过`struct`关键字定义,可以包含字段、构造函数及方法。例如,定义一个表示二维点的结构体,并实现计算距离原点的方法。使用时如同普通类型,可通过实例化并调用其成员。设计时推荐保持结构体不可变以避免副作用,并注意装箱拆箱可能导致的性能影响。掌握结构体有助于构建高效的应用程序。
130 7
|
4月前
|
Java Spring 自然语言处理
Spring 框架里竟藏着神秘魔法?国际化与本地化的奇妙之旅等你来揭开谜底!
【8月更文挑战第31天】在软件开发中,国际化(I18N)与本地化(L10N)对于满足不同地区用户需求至关重要。Spring框架提供了强大支持,利用资源文件和`MessageSource`实现多语言文本管理。通过配置日期格式和货币符号,进一步完善本地化功能。合理应用这些特性,可显著提升应用的多地区适应性和用户体验。
43 0
|
4月前
|
开发者
在.NET 中进行并发编程,究竟隐藏着哪些让开发者头疼不已的挑战?又该如何破解?
【8月更文挑战第28天】在现代软件开发中,并发编程的重要性日益凸显,但.NET开发者们却常常遇到资源竞争与死锁等挑战。例如,多线程对共享资源的访问可能导致数据不一致。以上提供了一个因缺乏同步机制而导致计数器结果出错的例子,并通过使用锁解决了该问题。此外,还介绍了一个产生死锁的代码片段,展示两个线程因互相等待对方持有的锁而陷入僵局。通过对这些挑战的理解和应对,可以提高软件的稳定性和效率。
29 0
|
4月前
|
传感器 数据采集 物联网
探索未来:.NET nanoFramework引领嵌入式设备编程革新之旅
【8月更文挑战第28天】.NET nanoFramework 是一款专为资源受限的嵌入式设备设计的轻量级、高性能框架,基于 .NET Core,采用 C# 进行开发,简化了传统底层硬件操作的复杂性,极大提升了开发效率。开发者可通过 Visual Studio 或 Visual Studio Code 快速搭建环境并创建项目,利用丰富的库和驱动程序轻松实现从基础 LED 控制到网络通信等多种功能,显著降低了嵌入式开发的门槛。
83 0
|
6月前
|
SQL 开发框架 安全
【.NET Core】深入理解任务并行库 (TPL)
【.NET Core】深入理解任务并行库 (TPL)
72 0
|
7月前
|
JSON 编解码 Go
Golang深入浅出之-HTTP客户端编程:使用net/http包发起请求
【4月更文挑战第25天】Go语言`net/http`包提供HTTP客户端和服务器功能,简化高性能网络应用开发。本文探讨如何发起HTTP请求,常见问题及解决策略。示例展示GET和POST请求的实现。注意响应体关闭、错误处理、内容类型设置、超时管理和并发控制。最佳实践包括重用`http.Client`,使用`context.Context`,处理JSON以及记录错误日志。通过实践这些技巧,提升HTTP编程技能。
85 1
|
7月前
|
Go 开发者
Golang深入浅出之-HTTP客户端编程:使用net/http包发起请求
【4月更文挑战第24天】Go语言的`net/http`包在HTTP客户端编程中扮演重要角色,但使用时需注意几个常见问题:1) 检查HTTP状态码以确保请求成功;2) 记得关闭响应体以防止资源泄漏;3) 设置超时限制,避免长时间等待;4) 根据需求处理重定向。理解这些细节能提升HTTP客户端编程的效率和质量。
82 1

热门文章

最新文章