一、多核、多cpu
(一)多核 Multicore
核是CPU最重要的部分。负责运算。核包括控制器、运算器、寄存器等单元。
多核就是指单个CPU中有多个核。
(二)多cpu Multiprocessor
多cpu就是一个系统拥有多个CPU。每个CPU可能有单个核,也可能有多个核。
(三)区别
多核CPU和多CPU的区别主要在于性能和成本。
多核CPU性能最好,但成本最高;
多CPU成本小,但性能较差。
二、并发、并行
(一)并发 Concurrency
并发是多个事件在同一时间段内发生,并不是在同一个时刻发生。通过频繁的分时交替运⾏,给⼈的感觉是同时运⾏,因为分时交替运⾏的时间是⾮常短的。比如执行0.001sA,然后暂停A,执行0.001sB,然后暂停B,执行0.001sA,如此反复。
(二)并行 Parallelism
并行是指多个事件在同一时刻发生。比如同时执行A和B。
(三)并发和并行的区别
并发是轮流处理,而并行是同时处理。
并发和并行的区别就是一个人同时吃三个菜和三个人每人吃一个菜;
单核不能并行,只能并发。
多核或者多cpu既能并行,也能并发。
1.并行,但不并发
执行完A才能执行B,但执行A时,其中的各个子任务可以在同一时刻同时执行。
2.并发,但不并行
执行A时,可以突然中断A转去执行B,执行完B后再去执行A。
3.并发且并行
执行A和B时不仅可以互相打断,还可以在同一时刻同时执行A和B。
三、进程、线程、协程
(一)进程 Process
进程是程序的一次执行过程。
每个进程都有⼀个独⽴的内存空间,拥有自己独立的堆和栈,既不共享堆,亦不共享栈。
同一个程序可以执行多次,这样就产生了多个进程,这多个进程都是独立的。类似于一个类产生多个实例。
进程由操作系统调度。
进程可以创建子进程。
(二)线程 Thread
线程是进程中的⼀个执⾏单元,负责当前进程中程序的执⾏,⼀个进程中⾄少有⼀个线程。
线程拥有自己独立的栈和共享的堆,共享堆,不共享栈。
线程亦由操作系统调度。
单线程和多线程
1.单线程
当进程只有一个线程时,就是单线程。
2.多线程
当进程有多个线程时,就是多线程。
(三)协程 Coroutine
协程,又称微线程,纤程。
协程和线程一样共享堆,不共享栈,但协程由程序员调度。同时,协程也无法使用多核。
(四)多线程与多进程的区别
多线程与多进程的目的都是想尽可能的利用CPU资源,减少CPU的空闲时间,特别是多核环境。
多进程:它最大的优点是稳定性高,因为一个子进程崩溃,不会影响其他进程;但创建进程的开销巨大,操作系统能同时运行的进程数也是有限的。
多线程:比多进程快,但是致命缺点是任何一个线程崩溃都造成整个进程的崩溃,因为所有线程共享进程的内存。
四、同步、异步
同步和异步关注的是消息通信机制。
(一)同步 synchronous
同步就是一个任务在执行某个请求的时候,如果这个请求返回需要很长时间,那么这个任务会不断询问是否已返回信息,直到收到返回信息才继续执行。
(二)异步 asynchronous
异步就是一个任务在执行某个请求的时候,它不会询问是否已返回,而是继续执行下面的操作,当返回信息时再通知这个任务。
(三)区别
区别在于消息通信方向相反。同步是调用方通知被调用方,异步是被调用方通知调用方。同步是调用方主动查询,异步是调用方被动接收。
比如,甲方委托乙方生产衣服,甲方隔两天问乙方生产完了吗,这叫同步;甲方不问,而是等到乙方生产完了通知甲方,这叫异步。
多线程和异步都可以避免阻塞,但异步和多线程不是一个概念。
多线程编程简单。有调度开销。并且线程间的共享变量可能造成死锁。
异步使用回调的方式,没有调度开销,在设计良好的情况下,处理函数可以不必使用共享变量,减少了死锁的可能。编写异步操作的复杂程度较高,程序主要使用回调方式进行处理,与普通人的思维方式有些出入,而且难以调试。
适用范围
当需要执行I/O操作时,使用异步操作比使用多线程更合适。
长时间CPU运算的场合,使用多线程更合适。例如耗时较长的图形处理和算法执行。
五、阻塞、非阻塞
阻塞与非阻塞关注的是程序在等待调用结果时候的状态。涉及CPU线程调度。
(一)阻塞 Blocking
就是调用结果返回之前,该线程会挂起,不释放CPU执行权,但也不做其它事情,只能等待,只有等到调用结果返回了,才能接着往下执行
(二)非阻塞 Non-blocking
就是在没有获取调用结果时,会释放cpu,cpu不会等待。
如果是同步的,通过轮询的方式检查有没有调用结果返回,如果是异步的,会通知回调
(三)区别
在于是否释放cpu
阻塞是cpu空转,白白浪费;
非阻塞是cpu不会空转。
例子
1.同步阻塞:
老张在厨房用普通水壶烧水,一直在厨房等着(阻塞),盯到水烧开(同步)
2.同步非阻塞:
老张在厨房用普通水壶烧水,在烧水过程中,就到客厅去看电视(非阻塞),然后时不时去厨房看看水烧开了没 (同步,主动询问)
3.异步阻塞:
老张在厨房用响水壶烧水,一直在厨房中等着(阻塞),不用盯着,而是等到水壶发出响声(异步),老张知道水烧开了
4.异步非阻塞:
老张在厨房用响水壶烧水,在烧水过程中,就到客厅去看电视(非阻塞),当水壶发出响声(异步),老张就知道水烧开了
例子
如果你想吃一份宫保鸡丁盖饭:
同步阻塞:你到饭馆点餐,然后在那等着,还要一边喊:好了没啊!
同步非阻塞:在饭馆点完餐,就去遛狗了。不过溜一会儿,就回饭馆喊一声:好了没啊!
异步阻塞:你到饭馆点餐,然后在那等着,不喊,而是等做好了给你端上来。
异步非阻塞:在饭馆点完餐,就去遛狗了。等做好了,饭店给你打电话。
六、io
I/O操作包括文件读写、数据库操作、网络请求等。
I/O操作不消耗CPU时间
同步阻塞IO(Blocking IO)BIO
同步非阻塞IO(Non-blocking IO)NIO
异步阻塞IO (IO multiplexing)IO多路复用
异步非阻塞IO 异步IO(Asynchronous IO)AIO
适用场景:
BIO适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,但程序直观简单易理解。
NIO适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂。
AIO使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂
七、多任务
要实现多任务,通常会设计成Master-Worker模式,Master负责分配任务,Worker负责执行任务;因此多任务环境下,通常是一个Master,多个Worker。
多任务可以使用多线程或者多进程。
如果用多线程实现Master-Worker,主线程就是Master,其他线程就是Worker。
如果用多进程实现Master-Worker,主进程就是Master,其他进程就是Worker。
无论是多线程还是多进程,只要Worker数量一多,效率肯定上不去,因为Worker一多,CPU就忙着切换工作,根本没多少时间去执行任务了。
是否采用多任务,还得考虑任务类型。
可以把任务划分为计算密集型和IO密集型。
计算密集型任务的特点是大量的计算,消耗CPU的资源,比如视频解码、计算圆周率。这种任务同时进行的数量应当等于CPU的核心数,这么做是为了降低切换任务所需要的时间,并且它还适合使用运行效率高的代码编写
IO密集型任务特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成。对于这类任务,任务越多,CPU效率越高,但也有一个限度。