1. 几个概念
1.1 并发
在操作系统的一个时间段中,有几个程序同时处于启动运行到运行完毕之间的状态,且这几个程序都在同一个处理机上运行。
并发又有伪并发和真并发:伪并发是指单核处理器的并发,真并发是指多核处理器的并发。
1.2 互斥
并发进程之间的制约关系有两种,即互斥和同步。
多个并发进程之间,因竞争使用临界资源而互相排斥执行的间接制约关系,叫作互斥。
例1:
例2:共享变量
设两个进程P1,P2,它们共享同一变量count,主要操作如下:
进程P1 | 进程P2 |
---|---|
R1:= count | R2:= count |
R1:= R1+1 | R2:= R2+1 |
count:= R1 | count:= R2 |
其中,R1和R2是处理机的两个通用寄存器。它们可以按各自独立的速度前进,所以运行的顺序也可能是:
进程 | 运行 |
---|---|
进程P1: | R1:= count |
进程P2: | R2:= count |
进程P1: | R1:= R1+1;count:= R1 |
进程P2: | R2:= R2+1;count:= R2 |
1.3 同步
在某些地方,多个并发进程需要相互等待或交换信息而产生的直接制约关系,叫做同步。
并发进程之间不是相互排斥临界资源,而是相互依赖的关系。进一步地说,同步关系就是前一个进程的输出作为后一个进程的输入;当第一个进程没有输出时,第二个进程必须等待。具有同步关系的一组并发进程,相互发送的信息称为消息或事件。
下面是一个司机和售票员同步的例子:
还有一个协作进程的例子:
用户作业程序的形式: Z=func1(x)∗func2(y) ,其中func1(x),func2(y)均是一个复杂函数,为了加速计算,按以下方法计算:
进程P1、P2分别计算 func1(x) 与 func2(y)
进程P1与P2计算结果相乘,获得结果Z
1.4 并行
在单核处理器的多道程序环境中,进程被交替执行,表现出一种并发的外部特征;在多核处理器的多道程序环境中,进程不仅可以交替执行,还可以重叠执行,即并行。
在多核处理器上,程序才可以实现并行处理。从而可知,并行是针对多核处理器而言。并行是同一时刻发生多个事件,具有并发的含义;但并发不一定并行,即并发事件之间不一定要同一时刻发生。
1.5 多线程
多线程是程序设计的逻辑层概念,它是进程中并发运行的一段代码。多线程可以实现线程间的切换执行。
1.6 异步
异步与同步是相对的:同步是顺序执行进程,执行完一个进程再执行下一个进程,需要进程之间等待、协调运行;异步是进程之间彼此独立,在等待其他进程的运行时,本进程继续做自己的事,不需要等待其他进程完成后再工作。
在多道程序环境下,进程以异步方式并发执行。
异步与多线程不是同等关系:异步是最终目的,多线程只是我们实现异步的一种方式。异步是让调用方法的主线程不用同步等待另一线程的完成,主线程可以同时做其它事情。
实现异步可以采用多线程技术或者交给另外的进程处理。
2. 事例理解
为了对以上概念更好地理解,举一个简单例子,假设我们要做烧开水,举杠铃100下, 洗衣服这3件事情。
烧开水:准备烧开水(1分钟), 等开水烧开(8分钟) , 关掉烧水机(1分钟)
举杠铃100下:举杠铃100下(10分钟)
洗衣服:准备洗衣服(1分钟), 等衣服洗完(5分钟),关掉洗衣机(1分钟)
2.1 单核处理器
- 同步执行
事情步骤安排:烧水:准备烧开水(1分钟), 等开水烧开(8分钟) , 关掉烧水机(1分钟);举杠铃100下:举杠铃100下(10分钟);洗衣服:准备洗衣服(1分钟), 等衣服洗完(5分钟),关掉洗衣机(1分钟)
做完3件事,花费的时间t = 1+ 8 +1 + 10 + 1+ 5 +1 = 27(分钟)
- 异步并行
在等待事情执行时,我(单核)可以切换出去,做别的事情。
事情步骤安排:准备烧开水(1分钟) + 准备洗衣服(1分钟) + 举50下杠铃 (5分钟)+ 关洗衣机(1分钟) + 举杠铃20下(2分钟)+ 关烧水机(1分钟) + 举30下杠铃(3分钟)
在等待衣服洗完(5分钟)时,我(单核)执行举50下杠铃(5分钟);在等待水烧开(8分钟)时,我(单核)执行举50下杠铃 (5分钟)+ 关洗衣机(1分钟) + 举杠铃20下(2分钟)。
做完3件事,花费的时间t = 1 + 1 + 5 + 1 + 2 + 1 + 3 = 14(分钟)
2.2 双核处理器
- 异步并行
核1:准备烧开水(1分钟)+ 举杠铃50下(5分钟)+ 等待(3分钟)+ 关掉烧水机 (1分钟)
核2:准备洗衣服(1分钟)+ 举杠铃50下(5分钟)+ 关掉洗衣机(1分钟) + 等待(3分钟)
其中,在等待水烧开(8分钟)时,核1执行举杠铃50下(5分钟),等待(3分钟);在等待衣服洗完(5分钟)时,核2执行举杠铃50下(5分钟)。
做完3件事,花费的时间t = 1 + 5 + 3 + 1 = 10(分钟),其中双核都等待了3分钟。
- 异步非并行
核1:举杠铃100下(10分钟)
核2:准备烧开水(1分钟)+ 准备洗衣服(1分钟)+ 等待(6分钟)+ 关掉烧水机(1分钟)+ 关掉洗衣机(1分钟)
其中,在等待水烧开(8分钟)时,核2执行准备烧开水(1分钟),准备洗衣服(1分钟),等待(6分钟);在等待衣服洗完(5分钟)时,核2执行等待(6分钟)。
做完3件事,花费的时间t =1 + 1 + 6 + 1 + 1 = 10(分钟)
2.3 多线程
- 单核处理器
线程1:准备烧开水(1分钟), 等水烧开(8分钟) , 关掉烧水机(1分钟)
线程2:举杠铃100下(10分钟)
线程3:准备洗衣服(1分钟), 等水烧开(5 分钟) , 关掉洗衣机(1分钟)
CPU最理想的切换方式:
线程1:准备烧开水(1分钟)+ sleep 1 + sleep 5 + sleep 1 + sleep 2 + 关开水(1分钟)
线程2:sleep 1+ sleep 1 + 举杠铃50(5分钟)+ sleep 1 + 举杠铃20(2分钟)+ sleep1 + 举杠铃30下(3分钟)
线程3:sleep 1 + 准备洗衣服(1分钟)+ sleep 5 +关洗衣机(1分钟)
最后使用了14分钟,与异步是一样的。但实际上是不一样的,因为线程不会按照我们设想的去跑。如果线程2举杠铃先跑,整个流程的速度就下来了。
2.4 异步和同步,多线程与异步,单核与多核的不同
异步和同步的区别:在IO等待时,同步不会切走,等待浪费了时间。
多线程比较容易地实现了异步切换的思想, 因为多线程较容易写。多线程本身还是以同步完成,但是比不上异步的效率。
多核的好处,就是可以同时做事情, 这个与单核不一样。如果都是独占CPU的作业,比如举杠铃。在单核情况下,多线程和单线程没有区别。