1、计算机硬件基本组成
一个计算机(冯·诺依曼结构)【主要】硬件组成:
- 主板:是“交通枢纽”,各个部件工作的所在平台,它负责将各个部件紧密连接在一起,各部件通过主板进行数据传输
- CPU:中央处理器(Central Processing Unit),决定电脑的性能等级。主要有3大组成部分
- 运算器:算术逻辑运算单元(ALU,Arithmetic Logic Unit),负责执行所有的数学和逻辑工作
- 控制器:控制单元(CU,Control Unit),控制计算机的所有其他部件,如输入输出设备以及存储器
- 寄存器:存储单元,包括CPU片内缓存和寄存器组,是CPU中暂时存放数据的地方
- 内存:将输入设备接收到的信息以二进制的数据形式存到存储器中
- RAM
- ROM
- CMOS
- 外存:辅助存储器,像硬盘等,能长期保存信息
- 显卡、网卡、声卡、电源、键盘、鼠标、显示器等
CPU是一块超大规模的集成电路,是一台计算机的运算核心(Core)和控制核心( Control Unit)。它的功能主要是解释计算机指令、处理计算机软件中的数据。
在初期,技术上一个CPU上只能由一个核心,随着技术的进步,我们能够把多个CPU继承到一起,这种CPU我们就叫它多核CPU
- 同一个时刻单个CPU核上只能运行一个任务。
- 1个CPU4核4线程:一个CPU指的是一个物理CPU,4核心可以看成是该CPU实际上由4个小的CPU组成,同一时刻每个小的CPU只能执行一个任务,所以这个CPU也可以说它是4核4线程
- 1个CPU4核8线程: 由于CPU的主频很快,切换任务很快,造成了一个CPU上有多个线程在运行一样。
总结:
- 多核 是指一个CPU有多个核心处理器,处理器之间通过CPU内部总线进行通讯。
- 多CPU是指简单的多个CPU工作在同一个系统上,多个CPU之间的通讯是通过主板上的总线进行的。
2、进程(process)、线程(thread)
进程:是操作系统(OS)进行资源(CPU、内存、磁盘、IO、带宽等)分配的最小单位;
- 是OS对正在运行的程序的一种抽象,是应用程序的执行实例,每个进程是由私有的虚拟地址空间、代码、数据和其它各种系统资源组成。
- 打开一个浏览器、一个聊天窗口分别是一个进程。进程可以有多个子任务,如聊天工具接收消息、发送消息,这些子任务是线程。
- 资源分配给进程,线程共享进程资源。
线程:是CPU执行的基本单位。
- 一个进程可由多个线程的执行单元组成,每个线程都运行在同一进程的上下文中,共享同样的代码和全局数据。
- 每个进程至少有一个主执行线程,它无需由用户主动创建,一般由系统自动创建。系统创建好进程后,实际上就启动了执行该进程的执行主线程,执行主线程以函数地址形式,即程序入口函数(如 main函数),将程序的启动点提供给操作系统。
- 主执行线程终止了,进程也就随之终止。
进程和线程的关系:
- 进程可以简单理解为一个容器,有自己独立的地址空间,其内部的各个线程共享该地址空间。
- 其实严格讲应该是线程能够获得CPU资源,进程对CPU资源的获取也是体现在线程上的。至于CPU内核数,和进程线程没直接关系。操作系统(OS)可以把某个进程部署在某个CPU核上,当然这要取决于系统设计。
线程数 是一种逻辑概念,是模拟出的CPU核心数。
线程是CPU调度和分配的最小单位,操作系统会根据进程的优先级和线程的优先级去调度CPU。一个计算机可以并发(同时)的线程数,等于计算机上的逻辑处理器的个数(CPU个数 *每个CPU核心数 *每个内核线程数)。
进程、线程是操作系统调度的,进程本身不会负责调度线程。在操作系统看来,线程和进程其实差不多,不同点是线程是迷你的进程,并且进程可以包含多个线程。
线程切换
- CPU给线程分配时间片(也就是分配给线程的时间),执行完时间片后会切换都另一个线程。
- 切换之前会保存线程的状态,下次时间片再给这个线程时才能知道当前状态。
- 从保存线程A的状态再到切换到线程B时,重新加载线程B的状态的这个过程就叫上下文切换。
- 而上下切换时会消耗大量的CPU时间。
线程开销
- 上下文切换消耗
- 线程创建和消亡的开销
- 线程需要保存维持线程本地栈,会消耗内存
进程是程序的一次执行 - 进程是一个实体,每一个进程都有它自己的内存地址段(heap、stack等),进程是执行中的程序。
- 程序是一个没有生命的实体,只有处理器赋予程序生命时,才能成为一个活动的实体。
进程和程序并不是一一对应的:
- 一般来说,一个进程肯定有一个与之对应的程序,而且只有一个。而一个程序有可能没有与之对应的进程(因为它没有执行)、也可能有多个进程与之对应(程序可以运行多次)。
- 一般情况下,写一个程序,没有单独开线程,那么默认这个程序的一次运行就是一个单进程;而如果调用了fork,这时将会有2个进程,调用thread,则这个进程就会有2个线程。
线程,程序执行的最小单元,每个程序都至少有一个线程,若程序只有一个线程,那就是它程序本身。单线程的进程可以简单地理解为只有一个线程的进程。一个进程在同一时间只做一件事,但有了多线程后,一个进程同一时间可以做多件事,每个线程可以处理不同的事务。无论系统有几个CPU,其实进程运行在单CPU上,多线程也可以是进程并发处理多个事务。一个线程阻塞不会影响另一个线程。
多线程的进程可以尽可能地利用系统CPU资源,但也不是线程越多越好,线程越多,CPU分配给每个线程的时间就越少。
线程 包含了表示进程内执行环节所必需的信息:标识线程的线程ID、一组寄存器值、栈、调度优先级和策略、信号屏蔽字、errno变量、线程私有数据。
对于内存而言,堆内存、代码区一般属于一个进程,但是栈却是属于一个线程的,且每个线程拥有一个独立的栈。
errno也是属于单个线程的,每个线程中的errno是独立的。
进程内所有信息对于线程是共享的,包括执行代码、全局变量、堆内存、栈、文件描述符。
总结:
进程和线程都是一个时间段的描述,是CPU工作时间段的描述:
- 进程就是上下文切换的程序执行时间总和 = CPU加载上下文+CPU执行+CPU保存上下文
- 线程是共享了进程的上下文环境,的更为细小的CPU时间段。
进程与线程的一个简单解释
计算机的核心是CPU,它承担了所有的计算任务。它就像一座工厂,时刻在运行。
假定工厂的电力有限,一次只能供给一个车间使用。也就是说,一个车间开工的时候,其他车间都必须停工。背后的含义就是,单个CPU一次只能运行一个任务。
进程就好比工厂的车间,它代表CPU所能处理的单个任务。任一时刻,CPU总是运行一个进程,其他进程处于非运行状态。
一个车间里,可以有很多工人。他们协同完成一个任务。
线程就好比车间里的工人。一个进程可以包括多个线程。
车间的空间是工人们共享的,比如许多房间是每个工人都可以进出的。这象征一个进程的内存空间是共享的,每个线程都可以使用这些共享内存。
可是,每间房间的大小不同,有些房间最多只能容纳一个人,比如厕所。里面有人的时候,其他人就不能进去了。这代表一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。
一个防止他人进入的简单方法,就是门口加一把锁。先到的人锁上门,后到的人看到上锁,就在门口排队,等锁打开再进去。这就叫"互斥锁"(Mutual exclusion,缩写 Mutex),防止多个线程同时读写某一块内存区域。
还有些房间,可以同时容纳n个人,比如厨房。也就是说,如果人数大于n,多出来的人只能在外面等着。这好比某些内存区域,只能供给固定数目的线程使用。
这时的解决方法,就是在门口挂n把钥匙。进去的人就取一把钥匙,出来时再把钥匙挂回原处。后到的人发现钥匙架空了,就知道必须在门口排队等着了。这种做法叫做"信号量"(Semaphore),用来保证多个线程不会互相冲突。
不难看出,mutex是semaphore的一种特殊情况(n=1时)。也就是说,完全可以用后者替代前者。但是,因为mutex较为简单,且效率高,所以在必须保证资源独占的情况下,还是采用这种设计。
操作系统的设计,因此可以归结为三点:
(1)以多进程形式,允许多个任务同时运行;
(2)以多线程形式,允许单个任务分成不同的部分运行;
(3)提供协调机制,一方面防止进程之间和线程之间产生冲突,另一方面允许进程之间和线程之间共享资源。
3、串行、并发、并行
这些概念对于进程、线程都适用。
3.1、串行
多个任务,执行时一个执行完再执行另一个。
3.2、并发(concurrency)
多个线程在单个核心运行,同一时间一个线程运行,系统不停切换线程,看起来像同时运行,实际上是线程不停切换。
即一个指令 和另一个指令交错执行,操作系统实现这种交错执行的机制称为:上下文切换。上下文是指操作系统保持跟踪进程或线程运行所需的所有状态信息,如寄存器文件的当前值、主存内容等
并发可以独立的并行执行,也可以串行执行
3.3、并行(parallelism)
每个线程分配给独立的核心,线程同时运行。
单核CPU多个进程或多个线程内能实现并发(微观上的串行,宏观上的并行);多核CPU线程间可以实现微观上并行。
总结:
- 1、单CPU中进程只能是并发,多CPU计算机中进程可以并行。
- 2、单CPU单核中线程只能并发,单CPU多核中线程可以并行。
- 3、无论是并发还是并行,使用者来看,看到的是多进程,多线程。
4、CPU处理程序
4.1、单核CPU处理程序
在单CPU计算机中,有一个资源是无法被多个程序并行使用的:CPU。
单进程多线程处理:
在一个程序里,有两个功能:听歌、发送消息,这就是单进程2线程。如果听歌线程获取了锁,那么这个线程将获取CPU的运行时间,其他线程将被阻塞。但CPU始终处于运行状态,影响计算时间的其实只是加锁、解锁的时间,并不会发生CPU空闲的现象,CPU利用率100%。
线程阻塞:一般是被动的,在抢占资源中得不到资源,被动的挂起在内存,等待某种资源或信号将它唤醒。(释放CPU,不释放内存)
多进程处理:
- 将听歌、发消息分别写出两个独立的程序,独立运行,与上面不同的是,如果进程间需要通信,比如交换数据,则会需要很多步骤,效率低。
4.2、多核CPU处理程序
单进程多线程处理:
线程可以跨核处理,进程之间则不能,如同支付宝不能访问QQ一样(安全性)。
跟单核对比:如果A核处理听歌线程阻塞,B核空闲,则CPU工作效率下降一半;没有阻塞时,QQ的A线程听歌、B线程发消息,多核CPU效率比单核快很多。
多进程多线程处理:
不同的程序,不可能一个进程融合QQ、支付宝、浏览器等
多核下线程数量选择:
-
计算密集型
程序主要为复杂的逻辑判断和复杂的运算。
CPU的利用率高,不用开太多的线程,开太多线程反而会因为线程切换时切换上下文而浪费资源。 -
IO密集型
程序主要为IO操作,比如磁盘IO(读取文件)和网络IO(网络请求)。
因为IO操作会阻塞线程,CPU利用率不高,可以开多点线程,阻塞时可以切换到其他就绪线程,提高CPU利用率。
总结:
- 提高性能的一种方式:提高硬件水平,处理速度或核心数。
- 另一种方式:根据实际场景,合理设置线程数,软件上提高CPU利用率。
进程:处理任务多,每个进程都有独立的内存单元,占用CPU资源相对较少。缺点是 进程间切换开销大。进程之间通信就如同两个程序之间的通信。
线程:处理任务相对较少,同时为了处理【并发】,多个线程共享内存单元,占用资源少。线程之间的通信就如同一个程序里的两个函数间通信,在函数里定义一个全局变量,两个线程(两个函数)都能用,线程间共享内存。
-
在现代Unix实现中,每个进程都可执行多个线程。夸奖线程想象为共享同一虚拟内存以及一干其他属性的进程。每个进程都会执行相同的函数代码,共享同一数据区段和堆。可是,每个线程都有属于自己的栈,用了装载本地变量和函数调用链接信息。
-
线程之间可以通过共享的全局变量进行通信。借助于线程API所提供的条件变量和互斥机制,进程所属限制之间得以相互通信并同步行为----尤其是在对共享变量的使用方面。另外,通过IPC和同步机制,线程间也能彼此通信
-
线程的主要优点在于协同线程之间数据共享(通过全局变量)更加容易,而且就某些算法而来,以多线程实现比多进程实现更加自然。另外,多线程应用能从多处理器硬件的并行处理中获益匪浅