C#并行编程(1):理解并行
什么是并行
并行是指两个或者多个事件在同一时刻发生。
在程序运行中,并行指多个CPU核心同时执行不同的任务;对于单核心CPU,严格来说是没有程序并行的。并行是为了提高任务执行效率,更快的获取结果。
与并发的区别:
并发是指两个或者多个事件在同一时段发生。
相对于并行,并发强调的是同一时段,是宏观上的同时发生。实际上,同一时刻只有一个任务在被执行,多个任务是分时地交替执行的。并发是为了更合理地分配资源。

如何实现并行
并行编程中我们只关注应用层面的并行,CPU的指令并行技术(指令流水等)不在我们的考虑范围。
从并行的意义来看,并行编程的目的无非是让多个CPU核心同时执行不同业务逻辑,获取优良的性能。但是,要怎样实现并行呢?实现并行,我们要借助进程和线程。
为了更好地管理计算机中运行的程序,计算机操作系统引入进程:
狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)。
广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。
——百度百科
由于进程拥有计算机资源,在创建、切换和撤销的过程中开销较大,这就限制了进程的并发程度;多核CPU的日渐普及的环境下,为提高并行粒度和并行计算的效率,引入了一种轻型的进程——线程:
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
——百度百科
线程包含于进程,同一进程的线程共享该进程的资源。线程出现后,线程取代进程作为操作系统调度和分派的基本单位,极大地减少了进程切换带来的性能损失,使得更细粒度和更高性能的并行得以实现。
进程的调度
一台计算机会运行很多程序,这些程序进程的数量多会大于CPU的核心数量。每个CPU核心同一时间只能执行一个进程,那操作系统是如何管理这些进程的呢?
当启动一个程序的实例时,操作系统将创建一个进程用来调度该程序实例。一个进程主要包含以下的信息:
进程控制块PCB,用于操作系统控制该程序实例
- 进程标识信息,如PID、名称等
- 现场信息,存放进程运行时处理器现场信息
- 控制信息,存放操作系统用于管理和调度进程的信息
- 专有的虚拟地址空间
- 句柄列表
- 程序实例的代码和数据,被映射到进程私有虚拟地址空间
程序状态字信息
进程的状态模型,如下图:

操作系统按照进程状态进行程序调度。
- 启动程序时,操作系统创建进程,此时进程为
新建态- 运行资源充足时,操作系统提交进程到
就绪状态,等待CPU选择或者抢占CPU执行 - 运行资源不足,如主存不够,操作系统会挂起进程,进程状态改为
就绪挂起,等待操作系统的恢复
- 运行资源充足时,操作系统提交进程到
- 就绪状态的进程
- CPU空闲时,会选择执行就绪状态的进程,被选中的进程进入
运行状态 - 进程优先级高时,将抢占当前正在执行进程的CPU资源,自身进入运行状态
- 操作系统会根据当前的可用资源,把就绪状态的进程挂起
- CPU空闲时,会选择执行就绪状态的进程,被选中的进程进入
- 就绪挂起的进程
- 当前没有就绪的进程,或者就绪挂起的某个进程具有较高的优先级,操作系统会将就绪挂起的进程恢复到就绪状态
- 运行状态的进程
- 进程自然结束、被强制终结或者出现无法解决的异常,将进入
终止状态,终止的线程不再参与进程调度 - 进程到达运行的时间片或者出现优先级高的进程抢占了CPU,进程会回到就绪状态等待调度
- 进程等待资源、I/O或者信号时,会进入
阻塞状态 - 优先级较高的进程抢占CPU,而此时系统资源不足,则正在运行的线程会被转入就绪挂起状态
- 进程自然结束、被强制终结或者出现无法解决的异常,将进入
- 阻塞状态的进程
- 进程阻塞的条件被满足,如等待的资源到位、I/O完成或收到信号,会进入就绪状态
- 进程在等待资源、I/O或者信号时,若系统检测到运行资源不足,会将阻塞的进程挂起进入
阻塞挂起状态
- 阻塞挂起的进程
- 当被挂起的进程具有较高优先级,同时由于其他进程的退出使资源充裕,进程会被转为阻塞状态
- 挂起的阻塞进程得到资源、I/O完成或者收到信号后,被转入就绪挂起状态
上述便是进程的调度过程,其中挂起的进程不占有任何资源。进程的调度很大程度是依赖于运行资源的;进程的优先级也是影响进程调度的重要因素;此外进程的调度还会涉及进程间的通信和同步问题,这里不做展开。
实际上,相对于进程,在并行编程中我们更关心线程,因为线程才是系统调度的基本单位。
线程的调度
在Windows系统中,每个进程至少有一个线程,每个线程都包含下面的内容:
- 线程内核对象,包含线程上下文(包含CPU寄存器信息的内存块)
- 线程环境块,包含线程的异常处理链首、本地存储数据等
- 用户模式栈,存储传给方法的局部变量和实参
- 内核模式栈,线程调用操作系统内核函数时,所传实参从用户模式栈复制到内核模式栈
- DLL线程连接和分离,线程创建和销毁时,所依赖的DLL需要收到通知才能执行相关资源的初始化和清理
从线程所含内容,我们可以知道线程的创建和销毁是有着时间和空间开销的,虽然这些开销相较于进程来说小了很多,但仍是影响程序效率的重要因素。特别是在并行处理的时候,线程的频繁创建和销毁将对并行性能产生极为严重的影响。
系统同一时间只给一个CPU核心分配一个线程,CPU执行该线程达一个时间片后,系统会给该CPU核心分配另一个线程。系统分配线程至CPU核心的过程就是线程的上下文切换过程,此间,系统将执行3个动作:
- 把CPU寄存器的值保存到正在运行的线程上下文中
- 从现有线程集合中选取一个线程准备分配
- 把选中线程上下文中保存的CPU寄存器值加载到CPU寄存器中
线程上下文切换会对程序性能带来很严重的影响,特别是切换到一个新进程的新线程时,很可能需要从RAM中加载代码和数据,大家知道RAM相对于CPU高速缓存太慢了。
线程的创建、切换及销毁都是有着不可忽视的开销,在追求高性能的程序中,我们应尽量少地线程,最优性能的线程数是机器CPU的核心数。当然,性能只是程序的一个方面,响应性和可靠性也是要关注的重点。
小结
并行在进程层面依赖于系统可用系统资源和CPU核心数,单核CPU的程序并行,实质上是并发;在线程层面则主要依赖于CPU核心数以及我们安排线程的方式。
后续将以.NET为例总结并发编程。
注:本文关于进程和线程的相关内容以Windows操作系统为参考。
C#并行编程(1):理解并行的更多相关文章
- OpenCL学习笔记(二):并行编程概念理解
欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld. 技术交流QQ群:433250724,欢迎对算法.技术.应用感兴趣的同学加入. 并行编程的需求是显而易见的,其 ...
- C#并行编程--命令式数据并行(Parallel.Invoke)
命令式数据并行 Visual C# 2010和.NETFramework4.0提供了很多令人激动的新特性,这些特性是为应对多核处理器和多处理器的复杂性设计的.然而,因为他们包括了完整的新的特性,开 ...
- C#并行编程之数据并行
所谓的数据并行的条件是: 1.拥有大量的数据. 2.对数据的逻辑操作都是一致的. 3.数据之间没有顺序依赖. 运行并行编程可以充分的利用现在多核计算机的优势.记录代码如下: public class ...
- 五 浅谈CPU 并行编程和 GPU 并行编程的区别
前言 CPU 的并行编程技术,也是高性能计算中的热点,也是今后要努力学习的方向.那么它和 GPU 并行编程有何区别呢? 本文将做出详细的对比,分析各自的特点,为将来深入学习 CPU 并行编程技术打下铺 ...
- 第五篇:浅谈CPU 并行编程和 GPU 并行编程的区别
前言 CPU 的并行编程技术,也是高性能计算中的热点,也是今后要努力学习的方向.那么它和 GPU 并行编程有何区别呢? 本文将做出详细的对比,分析各自的特点,为将来深入学习 CPU 并行编程技术打下铺 ...
- C#并行编程--命令式数据并行(Parallel.Invoke)---与匿名函数一起理解(转载整理)
命令式数据并行 Visual C# 2010和.NETFramework4.0提供了很多令人激动的新特性,这些特性是为应对多核处理器和多处理器的复杂性设计的.然而,因为他们包括了完整的新的特性,开 ...
- C#并行编程-Task
菜鸟学习并行编程,参考<C#并行编程高级教程.PDF>,如有错误,欢迎指正. 目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 ...
- C#并行编程-线程同步原语
菜鸟学习并行编程,参考<C#并行编程高级教程.PDF>,如有错误,欢迎指正. 目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 ...
- C#并行编程-PLINQ:声明式数据并行
目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 C#并行编程-线程同步原语 C#并行编程-PLINQ:声明式数据并行 背景 通过LINQ可 ...
- C#并行编程-PLINQ:声明式数据并行-转载
C#并行编程-PLINQ:声明式数据并行 目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 C#并行编程-线程同步原语 C#并行编程-P ...
随机推荐
- 《C#数据结构和算法》-排序
7.7 各种排序方法的比较与讨论 排序在计算机程序设计中非常重要,上面介绍的各种排序方法各有优缺点, 适用的场合也各不相同.在选择排序方法时应考虑的因素有: ( )待排序记录的数目 n 的大小: ( ...
- nginx 配置文件[转]
#运行用户 user nobody; #启动进程,通常设置成和cpu的数量相等 worker_processes 1; #全局错误日志及PID文件 #error_log logs/error.log; ...
- 深入分析Linux自旋锁【转】
转自:http://blog.chinaunix.net/uid-20543672-id-3252604.html 前言: 在复习休眠的过程中,我想验证自旋锁中不可休眠,所以编写了一个在自旋锁中休眠的 ...
- bzoj 1803: Spoj1487 Query on a tree III(主席树)
题意 你被给定一棵带点权的n个点的有根数,点从1到n编号. 定义查询 query(x,k): 寻找以x为根的k大点的编号(从小到大排序第k个点) 假设没有两个相同的点权. 输入格式: 第一行为整数n, ...
- 关于ajax请求,返回json数据格式
使用servlet测试 后台数据为:返回类型没有设置(方式一) String str = "["+ "{ id:1, pId:0, name:\"可折腾的父节点 ...
- MySQL双版本共存解决方案
案例是MySQL5.5(3306端口)和MySQL5.6(3307端口). 1. 修改C:\Program Files (x86)\MySQL\MySQL Server 5.6\下的my-xxx.in ...
- JS排序算法之快速排序
const Arr = [85, 24, 63, 45, 17, 31, 96, 50]; function quickSort(arr) { 80 if (arr.length <= 1) { ...
- Jmeter接口测试参数化实例图文示例
在实际测试中,不可能查询值测试一个输入值,还有其他测试数据,故引入参数化的概念,让一条用例循环执行,直到所有测试数据均测试完成,如下示例: Jmeter参数化有4种方法,本例仅介绍最普遍及简单的1个方 ...
- python3 + selenium 之窗口切换
窗口切换 此代码来源学习后对淘宝操作实践记录: 以下代码在Chrome61和IE11上正常运行,Firefox5.7上运行存在一些问题须改进,应该是火狐不兼容差link_text部分和循环经常报错,在 ...
- python 全栈开发,Day126(创业故事,软件部需求,内容采集,显示内容图文列表,MongoDB数据导入导出JSON)
作业讲解 下载代码: HBuilder APP和flask后端登录 链接:https://pan.baidu.com/s/1eBwd1sVXTNLdHwKRM2-ytg 密码:4pcw 如何打开APP ...