关于并行开发的一些概念整理【并发编程系列_1】
〇、前言
想很好的理解并行开发,需要了解的知识还是有很多的,下边就简单罗列几个概念。
一、相关概念简介
1、任务管理器中的 基准速度、插槽、内核、逻辑处理器
基准速度
就是处理器晶体管打开和关闭的速率,也就是 CPU 运作的参考速度。听起来像是速度越快越好,但是也有一定的局限性,也需要合适体量的内核才能发挥效用,另外速度的提高也伴随着更高的能耗。
插槽
指的是主机支持插入几个物理 CPU。
内核
又叫物理内核,一个物理 CPU 可以包含多个物理内核。
逻辑处理器
即逻辑 CPU,一个物理内核可以包含多个逻辑 CPU。计算机设备管理器中显示的处理器个数对应的就是逻辑处理器的个数。
举个例子:
如下图,因为只有一个插槽,所以就只能装机一个物理 CPU,然后一个物理 CPU 包含 6 个物理内核,一个内核中包含两个逻辑处理器,即 1 x 6 x 2 = 12。
2、进程与线程
进程-Process
指的是程序的一次执行的过程,是一个动态概念,也是程序在执行过程中分配和管理资源的基本单位。
线程
是 CPU 调度和分派的基本单位,它可与同属一个进程的其他的线程共享进程所拥有的全部资源。每个进程都会有一个主线程(Main Thread)。
进程、线程、逻辑处理器之间的关系
线程是进程的一部分,一个线程只能属于一个进程,而一个进程有一个到多个线程。
进程和线程的根本区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位。
逻辑处理器的个数,代表计算机同时能有同样个数的线程在工作。
3、硬件线程和软件线程
硬件线程也叫逻辑处理器或逻辑内核,同样的,一个物理内核就可以包含多个硬件线程。
软件线程(Software Thread)就是我们常提到的线程。
Windows 将每一个硬件线程识别为一个可调度的逻辑处理器,每一个逻辑处理器可以运行软件线程代码,运行多个软件线程的进程可以充分发挥硬件线程和物理内核的优势,并行地运行指令。
Windows 会给每一个可用的硬件线程分配一块块的处理时间,并通过这种方式运行上百个千个软件线程。
4、并行与并发
并发:关键是你有处理多个任务的能力,不一定要同时。
并行:关键是你有同时处理多个任务的能力。
所以区别它们最关键的点就是:是否是“同时”。可见,能够“同时”的并行,效率相对更高。
举例:假如你吃饭吃到一半,电话来了,然后:
- 你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。(按顺序一个一个处理)
- 你停了下来接了电话,接完后继续吃饭,这说明你支持并发。(都可以做,但当时只能做一件事)
- 你一边打电话一边吃饭,这说明你支持并行。(可以同时做多件事)
5、单线程与多线程
单线程
就是一个进程只有一个线程。程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。
多线程
就是一个进程有多个线程。在程序执行时,所有线程会交替执行。后面的线程不用等待前面的线程处理完毕。
多线程根据并行和并发又有不同的情况。
- 在并发时,多个线程会抢占cpu资源执行一块逻辑,没有抢到cpu资源的就会进入等待状态,等cpu空闲后继续抢占资源。这就像一个车间只有一台机器,所有的工人都有相同的任务,他们都要使用这台机器,抢到的工人就执行任务,没有抢到的工人就等待任务执行完毕后,继续抢这台机器。
- 在并行时,多个线程会同时执行一块代码逻辑。就像一个车间有四台机器,四个工人分别使用四台机器,同时执行任务,不用等待其它工人任务执行完毕。
使用场景的区别:
- 单线程:当有三件事要处理,乙 需要在 甲 之后处理,同时 丙 需要在 乙 之后,这种事件有特定的先后顺序(甲-->乙-->丙)。
- 多线程:需处理的多件事互相独立。例如下载大文件时的进度条和实际下载进度,就需要一边显示进度一边进行下载。
6、上下文切换
CPU 通过时间片轮转算法来循环执行线程任务,每次执行并不是直接将任务完成。这种切换用时很短,从而使各个程序的运行从表面上看是同时进行的。切换时会保存之前的线程任务状态,当切换到该线程任务的时候,会重新加载该线程的任务状态。而这个从保存到加载的过程称之为上下文切换。
比如我们拿了两本书,一本中英文词典,一本英文书,在读英文书时发现某个单词不认识,于是便打开中英文词典看单词的汉译,但是放下英文书之前,大脑必须记下这本书读到了多少页的多少行,等查询完单词之后,能够继续读这本书。但这样的切换是会影响读书效率的,同样上下文切换也会影响多线程的执行速度。
由于线程的状态保存和加载都是耗时的,所以在执行串行化代码时,多线程相比单线程效率低。
7、异步、同步、响应、函数式编程
异步编程
是并发的一种形式,老式的异步编程采用回调的机制,以避免创建不必要的线程。异步编程的核心概念是异步操作,即启动的操作会在一定时间后才能完成,这个操作正在执行,却并不会阻塞原来的线程,启动了这个操作的线程还可以继续执行其他任务,等操作完成时,它会调用回调函数,已让程序知道操作已经结束了。
同步编程
它和单线程的效果类似,进程之间的关系不是相互排斥临界资源的关系,而是相互依赖的关系。即前一个进程的输出作为后一个进程的输入,当第一个进程没有输出时第二个进程必须等待。具有同步关系的一组并发进程相互发送的信息称为消息或事件。其中并发又有伪并发和真并发,伪并发是指单核处理器的并发,真并发是指多核处理器的并发。
响应编程
是另一种形式的并发编程,它基于异步事件,而不是异步编程中的异步操作,异步操作有一个开始执行的概念,但是异步事件可以在任何时间发生,并且可以发生多次,大概类似于用户响应事件的概念。它是一种声明式的编程模式,程序在该模式中对事件做出与之对应的响应。
函数式编程
大多数并发编程,其本质都是函数式的,函数式编程有两个原则,一个是简洁,有非常清晰的输入和输出,而且尽可能的避免全局或者共享变量。另一个原则就是不变性,指一段数据不能被修改,程序永远不需要对这些数据进行同步,就是非常简单的输入数据,输出数据。
8、主线程、前台线程、后台线程 --20230714
当一个程序启动时,就有一个进程被操作系统(OS)创建,与此同时一个线程也立刻运行,该线程通常叫做程序的主线程(Main Thread),因为它是程序开始时就执行的,如果你需要再创建线程,那么创建的线程就是这个主线程的子线程。
上述中新建的子线程可以是前台线程,也可以是后台线程,他们具有以下特点:
- 前台线程必须全部执行完,即使主线程关闭掉,这时进程仍然存活。
- 后台线程在未执行完成时,如果前台线程关掉,则后台线程也会停掉,且不抛出异常。
也就是说,前台线程与后台线程唯一的区别是后台线程不会阻止进程终止,可以在任何时候将前台线程修改为后台线程。
所以,只有在确认线程被系统随意终止没有不利影响时,才应该使用后台线程。如果线程正在执行必须完成的敏感操作或事务操作,或者需要控制关闭线程的方式以便释放重要资源,则使用前台线程。
9、线程池的全局队列、本地队列--20230720
对于线程池而言,并非是一个工作项在加入时直接交给线程去执行,而是直接放到一个队列系统中,其中的队列总共分两种,针对 全部线程的全局队列、针对某一线程的本地队列。线程池中的每一个线程都在执行 while(true) 的循环,从这个队列系统中领取并执行任务。
对于大多数情况下,我们都是在线程池外将任务添加到线程池中。那如何将任务项直接加到某一线程的本地队列呐?下面给出答案:
- 在 ThreadPool.QueueUserWorkItem 的重载方法 ThreadPool.QueueUserWorkItem<TState>(Action<TState> callBack, TState state, bool preferLocal) 里有一个 preferLocal 参数。
- 调用不带 preferLocal 参数的 ThreadPool.QueueUserWorkItem 方法重载,任务会被放到全局队列。
- 当 preferLocal 为 true 的时候,如果调用 ThreadPool.QueueUserWorkItem 代码的线程正好是个线程池里的某个线程,则该任务就会进入该线程的本地队列中。
- 在线程池外的线程中调用,不管 preferLocal 传的是什么,任务都会被放到全局队列。
线程池中有空闲的工作线程时,就会按照工作项在队列里的顺序 FIFO(先进先出)取出并执行。
全局队列是共享资源,所以内部会有锁的概念。当业务比较复杂时,全局队列操作频繁,就会导致整体性能下降。
详情可参考:https://www.cnblogs.com/eventhorizon/p/15316955.html
10、、、
部分参考:并行编程相关概念 C#并发编程相关名词解释 单线程和多线程? 异步,多线程和并行的区别? 并发与并行的区别是什么?
注:个人整理,难免有疏漏,请大方的指正或补充,博主也会第一时间进行修改或补充。后续如果博主发现有需要补充的也会持续更新。
本文来自博客园,作者:橙子家,欢迎微信扫码关注博主【橙子家czzj】,有任何疑问欢迎沟通,共同成长!