杂记(二十) 线程和内核什么关系 | CPU,Core,GPU,进程,线程 |

线程和内核什么关系?

我猜题主在说线程与CPU核心之间的关系吧。

实际上CPU核数与线程数可以没有任何关系,注意是可以,这两个一个是硬件概念,一个是软件上的概念,但毕竟是CPU核心在执行线程,因此这里有一点的关联,我们慢慢讲起。

炒菜与线程

实际上CPU和厨师一样,都是按照菜谱(机器指令)去执行某个动作,从操作系统的角度讲当CPU切换回用户态后,CPU执行的一段指令就是线程,或者说属于某个线程

img

这和炒菜一样,我可以按照菜谱抄鱼香肉丝,那么炒菜时这就是鱼香肉丝线程;我可以按照菜谱抄宫保鸡丁,那么炒菜时这就是宫保鸡丁线程。

厨师个数就好比CPU核心数,炒菜的样数就好比线程数,这时我问你,你觉得厨师的个数和可以同时抄几样菜有关系吗?答案当然是没有。

CPU的核心数和线程个数没有什么必然的关系

单个核心上可以跑任意多个线程,只要你的内存够就行;计算机系统内也可以有任意多核数,只要你有钱就行。

关于CPU更详细的讲解请参考这篇:

看到这个答案你是不是觉得有点疑惑、有点疑问、有点不明所以,这好像和其它人说的不一样啊!别着急,我们慢慢讲。

傻傻的CPU

CPU根本不理解自己执行的指令属于哪个线程,CPU也不需要理解这些,CPU需要做的事情就是根据PC寄存器中的地址从内存中取出后执行,其它没了

img

你看CPU才不管你系统内有多少线程。有多少线程是谁需要来关心的呢?是操作系统。

线程是操作系统的把戏。

操作系统与多任务

很久很久以前,计算机一次只能执行一个任务,你不能像现在这样在计算机上一边看电影一边在下小电影,哦,不对,一边写代码,一边下载资料。

要么你先写代码,写完代码后再去下资料,要么你先下资料然后再写代码,总之,这两个任务不能同时进行

这显然很不方便,就这样,多任务——Multi-Tasking,诞生了。

img

你CPU不是只知道执行机器指令吗?很好,那我操作系统就通过修改你的PC寄存器,让你CPU执行A任务的机器指令一段时间,然后下一段时间再去执行B任务的机器指令,再然后下一个时间段去执行C任务的机器指令,由于每一段时间非常少,通常在毫秒级别,那么在人类看来A、B、C三个任务在“同时”运行。

这就是多任务的本质,多任务也就是指我们平时所说的进程以及线程,关于这些概念的来源请参考这篇文章。

值得注意的是,计算机系统还在单核时代就已经有多线程的概念了,我们之前说过,即使是单核也可以执行多个线程,那么有的同学可能会有疑问,在单核的系统中开启多个线程有什么意义吗?

单核与多线程

假设现在有两个任务,任务A和任务B,每个任务需要的计算时间都是5分钟,那么无论是任务A和任务B串行执行还是放到两个线程中并行执行,在单核环境下执行完这两个任务总需要10分钟,因此有的同学觉得单核下多线程没什么用。

实际上,线程这个概念为程序员提供了一种编程抽象,我们可以把一项任务进行划分,然后把每一个子任务放到一个个线程中去运行。

img

假如你的程序带有图形界面,某个UI元素背后需要的大量运算,这时为了防止执行该运算时UI产生卡顿,那么可以把这个运算任务放到一个单独的线程中去。

因此如果你的目的是防止当前线程因执行某项操作而不得不等待,那么在这样的应用场景下,你根本就不需要关心系统内是单核还是多核以及有多少个核。

阻塞式I/O

这也是使用线程的经典场景。

如果没有线程,那么执行阻塞式I/O时整个进程会被操作系统暂停,但如果你开启两个线程,其中一个线程被阻塞时另一个线程依然可以继续向前推进。这样的话你就不需要去使用反人类的异步IO了。

当然,这一切的前提是你的场景不涉及高性能以及高并发,如果涉及的话那这就是另一个话题了。在这种简单的场景下,你创建线程时也不需要关心系统中是单核还是多核。

多核时代

实际上,线程这个概念是从2003年左右才开始流行的,为什么?因为这一时期,多核时代到来了。

img

之所以产生多核,是因为单核的性能提升越来越困难了。尽管采用多进程也可以充分利用多核,但毕竟多进程编程是很繁琐的,这涉及复杂的进程间通信机制、进程间切换的较高性能损耗、进程间内存相互隔离带来的对内存消耗等。

线程这个概念很好的解决了上述问题,开始成为多核时代的主角,要想充分利用多核资源,线程是程序员的首选工具。

真正的并行

有了多核后,运行在两个线程中的任务A和任务B实现了真正的并行。此前这样一句话广为引用,这句话是这么说的:

threads are for people who can’t program state machines

“线程是为那些不懂状态机的人准备的”,这句话在单核时代有它的道理,因为在单核时代,所有的任务都不是在同时向前推进,而是“交错”前进,A前进一点,然后B前进一点,线程并不是实现这种“伪并行”唯一的方法,状态机也可以。

img

但在多核时代,这句话就不再适用了,对于大多数程序员来说多进程多线程几乎是充分利用多核资源的唯一方法。如果你的场景是想充分利用多核,那么这时你的确需要知道系统内有多少核数,**一般来说你创建的线程数需要与核数保持线性关系。**也就是说,如果你的核数翻倍,那么创建的线程数也要翻倍。

需要多少线程?

值得注意的是,线程不是越多越好。

如果你的线程是不涉及任何I/O、没有任何同步互斥之类的纯计算类型,那么每个核心一个线程通常是最佳选择。但通常来说,线程都需要一定的I/O,可能需要一定的同步互斥,那么这时适当增加线程可能会提高性能,但当线程数量到达一个临界值后性能开始下降,这时线程间切换的开销将显著增加。

这里之所以用适当这个词,是因为这很难去量化,只能用你实际的程序根据真正的场景进行测试才能得到这个值

现在你应该知道了吧,线程数和CPU核心数可以没有任何关联,如果在使用线程时仅仅针对上述提到的几个简单场景,那么你根本不需要关心CPU是单核还是多核。但当你需要利用线程充分发挥多核威力时,通常情况下你创建的线程数与核数要保持一种线性关系,当然也要看你的线程属于什么类型,这主要指CPU密集型和I/O密集型。

CPU密集型

所谓CPU密集型就是说处理任务不需要依赖外部I/O,比如科学计算、矩阵运算等等。在这种情况下只要线程的数量和核数基本相同就可以充分利用CPU资源。

img

I/O密集型

这一类任务可能计算部分所占用时间不多,大部分时间都用在了比如磁盘I/O、网络I/O等,

img

这种情况下就稍微复杂一些了,你需要利用性能测试工具评估出用在I/O等待上的时间,这里记为WT(wait time),以及CPU计算所需要的时间,这里极为CT(computing time),那么对于一个N核的系统,合适的线程数大概是N * (1 + WT/CT),假设I/O等待时间和计算时间相同,那么你大概需要2N个线程才能充分利用CPU资源,注意这只是一个理论值,具体设置多少需要根据真实的业务场景进行测试。

现在你应该知道了吧,线程数和CPU核心数到底有没有关系取决于你的应用场景。

CPU,Core,GPU,进程,线程
这是为自己写的笔记,一方面加深理解,一方面方便后续查阅,希望也能方便大家查阅~

概念

集群:只要是几台机器堆在一起,就叫集群。

分布式:一个程序或系统,只要运行在不同机器上,就叫分布式。

中央处理器 CPU:一个物理概念,负责读取、编译和执行指令,它主要的部分有:控制器(Control Unit,CU)、运算器(Arithmetic and Logic Unit, ALU)、寄存器(Register)、高速缓存器(Cache)以及总线。(通常CPU数量指的是电脑中有多少个CPU卡槽或者CPU硬件数;一般家用电脑中只有一个CPU,服务器中会有多个)。

内核 Core:一个物理概念,是读取和执行程序指令的独立处理单元,是CPU最重要的组成部分。CPU中心隆起的芯片就内核。(一个CPU可以有多个核,比如我PC的CPU就有两个核,我们服务器的一个CPU有64个核)

虚拟核(逻辑核、线程)Thread:一个逻辑概念,如果一个核可同时执行2个线程,那么该核的虚拟核数为2。(通常一个核某一个时刻只能执行一个线程,也就是一个核的线程数是1,但由于多线程技术(Simultaneous Multithreading,SMT)的出现,使得一个核具备多线程同时执行的能力。)

图形处理器 GPU:一个物理概念,显卡的核心。无法单独工作,必须由CPU进行控制调用才能工作。

进程:程序运行的一个实体的运行过程,操作系统进行资源(包括内存、磁盘IO等)分配的最小单位,系统赋予其独立的内存地址空间;进程之间在资源上是相互独立的,但因为CPU资源有限,所以进程之间会相互制约。

线程:进程运行和执行的最小调度单位;同一进程内的线程具有相同的地址空间,共享进程内的资源,可以相互通信相互影响。线程是一个基本的CPU执行单元,也是程序执行过程中的最小单元,由线程ID、程序计数器、寄存器集合和堆栈共同组成。线程的引入减小了程序并发执行时的开销,提高了操作系统的并发性能。

相互关系
一台电脑可以有多个CPU,一个CPU可以有多个核,核是CPU的基本计算单元,IO读取控制、中断处理,等等资源在所有的核之间共享。

一个CPU在同一时刻最多只能运行X个线程,其中X=CPU核数 * 虚拟核数,多出来的那些线程必须等待操作系统的调度,或者抢占正在运行的线程。

一个进程可以有多个线程,一个线程只能属于一个进程,但我们打开的微信是一个进程,微信有很多子任务,比如接收消息、发送消息,一个子任务就是一个线程。资源分配给进程,线程共享进程资源。

如果服务器中有多个CPU,那么多个进程可以在多个CPU中并行计算,一个进程在同一时间段只能在一个CPU中运行,如果进程数小于CPU数,则未使用过的CPU会空闲。同一进程中的多个线程可以并发执行。

并发处理(Concurrency Processing):指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个虚拟核上运行,如果系统只有一个虚拟核,则它根本不可能真正同时运行一个以上的线程,它只能把运行时间划分成若干个时间段,再将时间段分配给各个线程执行,在某一个时间段内,只有一个线程在运行,其它线程处于挂起状态。这种方式我们称之为并发处理。

并行处理(Parallel Processing):当系统有一个以上的CPU(或虚拟核)时,一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行处理。

串行、并行、并发(图片来自 https://www.jianshu.com/p/4ed56408da59)
CPU与GPU的区别

CPU GPU
内核数少 内核数多(众核)
每个核相对复杂,都有足够大的缓存和足够多的数字逻辑运算单元 每个核相对简单,拥有的缓存和数字逻辑运算单元也少
擅长处理具有复杂计算步骤和复杂数据依赖的计算任务 擅长对大规模数据进行相同的简单的操作
串行工作 并行工作
缓存多 缓存少
线程数少 线程数多
运算器、寄存器少 运算器、寄存器多
Linux系统中查看各种信息的方式
查看 cpu 个数:

$ cat /proc/cpuinfo| grep “physical id”| sort| uniq| wc -l
查看每个CPU中内核数:

$ cat /proc/cpuinfo | grep “cpu cores” | uniq
查看虚拟核数(以下两者都可以):

$ cat /proc/cpuinfo| grep “processor”| wc -l
$ nproc --all
查看CPU型号

$ cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c
查看CPU信息

$ lscpu
Architecture: x86_64 #架构
CPU op-mode(s): 32-bit, 64-bit #运行方式
Byte Order: Little Endian #字节顺序
CPU(s): 32 #虚拟核数量
On-line CPU(s) list: 0-31 #在线的CPU编号
Thread(s) per core: 2 #每个内核的虚拟核数(逻辑核数,线程数)
Core(s) per socket: 8 #每个CPU插槽的内核数(每个CPU的内核数)(通常一个CPU插槽插一个CPU)
Socket(s): 2 #CPU插槽数(CPU数量)
NUMA node(s): 2 #非统一内存访问(Non-uniform memory access,NUMA))节点
Vendor ID: GenuineIntel #cpu厂商ID
CPU family: 6 #cpu系列
Model: 63 #型号编号
Model name: Intel® Xeon® CPU E5-2680 v3 @ 2.40GHz #CPU型号名称
Stepping: 2 #步进
CPU MHz: 2494.222 #CPU主频
BogoMIPS: 4988.44
Hypervisor vendor: KVM #虚拟化架构
Virtualization type: full #cpu支持的虚拟化技术
L1d cache: 32K #一级缓存
L1i cache: 32K #一级缓存
L2 cache: 256K #二级缓存
L3 cache: 30720K #三级缓存
NUMA node0 CPU(s): 0-7,16-23 #node0包含第0-7,16-23个虚拟核
NUMA node1 CPU(s): 8-15,24-31 #node1包含第8-15,24-31个虚拟核
.
.
.
查看CPU使用情况

$ top

图片来自https://www.cnblogs.com/mengchunchen/p/9669704.html
第一行(top):15:24:36 系统当前时刻;14 days 系统启动后到现在的运作时间;3 users 当前登录到系统的用户,更确切的说是登录到用户的终端数;load average 当前系统负载的平均值,后面的三个值分别为1分钟前、5分钟前、15分钟前进程的平均数,一般的可以认为这个数值超过虚拟核数目时,CPU 将比较吃力的负载当前系统所包含的进程。

第二行(Tasks):288 total 当前系统进程总数;1 running 当前运行中的进程数;287 sleeping 当前处于等待状态中的进程数;0 stoped 被停止的系统进程数;0 zombie 僵尸进程数。

第三行(Cpus):7.3% us 用户空间占用CPU百分比;2.0% sy 内核空间占用CPU百分比;0.0% ni 用户进程空间内改变过优先级的进程占用CPU百分比;90.4% id 空闲CPU百分比;0.3% wa 等待输入输出的CPU时间百分比。

第四行(Mem):2042616 total 物理内存总量;1770116 used 使用的物理内存总量;272500 free 空闲内存总量;163912 buffers 用作内核缓存的内存量。

第五行(Swap):表示类别同第四行(Mem),但此处反映着交换分区(Swap)的使用情况。通常,交换分区(Swap)被频繁使用的情况,将被视作物理内存不足而造成的。2094076 total 交换区总量;45052 used 使用的交换区总量;2049024 free 空闲交换区总量;346624 cached 缓冲的交换区总量。

最下部分的进程列表栏:以 PID 区分的进程列表将根据所设定的画面更新时间定期的更新。通过 top 内部命令可以控制此处的显示方式:

PID:进程的ID
  USER:进程所有者
  PR:进程的优先级别,越小越优先被执行
  NInice:值
  VIRT:进程占用的虚拟内存
  RES:进程占用的物理内存
  SHR:进程使用的共享内存
  S:进程的状态。S表示休眠,R表示正在运行,Z表示僵死状态,N表示该进程优先值为负数
  %CPU:进程占用CPU的使用率
  %MEM:进程使用的物理内存和总内存的百分比
  TIME+:该进程启动后占用的总的CPU时间,即占用CPU使用时间的累加值。
  COMMAND:进程启动命令名称

查看GPU信息及使用情况

$ nvidia-smi

Fan:显示风扇转速,数值在0到100%之间,是计算机的期望转速,如果计算机不是通过风扇冷却或者风扇坏了,显示出来就是N/A;

Temp:显卡内部的温度,单位是摄氏度;

Perf:表征性能状态,从P0到P12,P0表示最大性能,P12表示状态最小性能;

Pwr:能耗表示;

Bus-Id:涉及GPU总线的相关信息;

Disp.A:是Display Active的意思,表示GPU的显示是否初始化;

Memory Usage:显存的使用率;

Volatile GPU-Util:浮动的GPU利用率;

Compute M:计算模式;

参考:

https://www.guru99.com/cpu-core-multicore-thread.html

何健超:cpu 核心数与线程数

认识cpu、核与线程 - jiajun_geek - 博客园

性能基础之CPU、物理核、逻辑核概念与关系 - 云+社区 - 腾讯云

进程与线程,单核与多核

CPU 和 GPU 的区别是什么?

https://theydiffer.com/difference-between-a-cpu-and-a-core/

猜你喜欢

转载自blog.csdn.net/weixin_44302770/article/details/135277006