把学习当成一种习惯
选择往往大于努力,越努力越幸运

并发、并行

并发、并行只是一字之差,但是两者的含义却是不同的.

引用Rob Pike的经典描述 :

  • 并发是同一时间应对多件事情的能力.(处理多个事情(任务))
  • 并行是同一时间动手做多件事情的能力.(执行多个事情(任务))

并发

  • 并发程序含有多个逻辑上的独立执行块,它们可以独立地并行执行,也可以串行执行.并发关注的是同一时间应对多件事情的能力.

  这句话很抽象,先来看看前半部分的句子 : 什么是并发程序、多个逻辑上的独立执行块?
  基于上一篇文章OS基础:线程模型(一)所了解的程序、进程、线程概念,再结合文章中计算机科学家做蛋糕的例子来理解.我们知道,制作蛋糕的步骤如果要再细分的话,有搅拌鸡蛋、搅拌面粉、切水果、用蛋糕容器制作蛋糕、把蛋糕放入烤箱等等步骤,但是呢,计算机科学家是第一次做蛋糕,所以自己一个人从头干到尾的跟着食谱的步骤来制作蛋糕,所以这个只是一个单任务的程序(食谱),并不是一个并发的程序(食谱). 这里小结一下 : 这种单任务的程序不是【并发】程序,所以对应的只是单个逻辑上的独立执行块.
  我们假设计算机科学家已经是一位制作蛋糕的高手,那么他已经很熟练,可以自己"优化"食谱 : 把搅拌鸡蛋、搅拌面粉、切水果等步骤拆出来为不同的任务,即把一个任务拆分成多个任务来完成;"优化"的食谱"可以"让更多的人一起把任务做得更高效,而这个"优化"的程序(食谱)就是一个多任务的【并发】的程序;这里需要注意的是 : 拆分多个任务只是"可以"让任务更高效的完成,而不是"必然"让任务更高效的完成,是不是高效的问题后文再说.这里小结一下 : 这种多任务的程序就是【并发】程序,所以对应的是多个逻辑上的独立执行块,即每个任务都有各自逻辑上的独立执行块.【并发】程序可以让更多的人参与进来,具体同一时刻多少人参与进来,要看CPU是几核的.

  • 并发程序 : 同一时间处理多个任务的程序就是【并发】程序,每个任务都有逻辑上的独立执行块.

  对于现代OS而言,多道程序是抢夺式多任务、【并发】运行的,但真正实际只有一个进程在运行,所以是串行的,并非并行.那对于一个【并发】程序,即运行着的【并发】进程,你需要用编程语言告诉操作系统你的程序的一些步骤是【并发】的,或者说你是如何做到你的程序的多个任务之间协调的呢,大牛们为了解决这个问题,进而引入了 "并发模型".

并发模型

例如以下几种模型 :

  • 线程与锁模型 : 比如Java;
  • Fork/Join模型;
  • Actor模型;
  • CSP模型 : 比如Go的goroutine.
  • ......

  由于本人目前是做Java,所以对线程与锁模型有更加深入的理解,会独立一篇文章结合Java来说说线程与锁这个并发模型.同时,Java并没有协程,但是相对应的Java的新特性 Project Loom,是值得期待的Javaroutine.

并行

  • 并行程序解决问题的速度往往比串行程序快得多,因为可以同时执行整个任务的多个子任务.并行关注的是同一时间执行多件事情的能力.

  计算机科学家有了自己"优化"的多任务的【并发】程序,但是这只是一种可以多人一起做蛋糕的一种方案,并不知道实际有多少人可以一起做蛋糕,换句话说,你有了一个"可以"高效的执行方案,但能不能【并行】的执行取决于执行任务的人数,举个例子,计算机科学家原本安排搅拌鸡蛋、搅拌面粉、准备水果这三个步骤分别是给不同的三个人来同时执行,但是由于家里就他一个人,所以只能一个人一个步骤一个步骤干,如果家里有另外一个人,那么他就可以分担一些步骤给他,让他一起做蛋糕,这两个人同时的在做蛋糕,就是【并行】.
  在计算机领域中,【并发】程序能不能【并行】,取决于服务器有多少核CPU.

并发与并行的关系

  一个【并发】的程序的巨大优势就是可以得到【并行】的好处,在1核CPU和4核CPU运行的【并发】程序,在性能上还是有明显不同,毕竟更多的人参与做蛋糕,但是这里就引入了沟通、协调成本.
  为什么【并发】程序只是"可以"让任务更高效的完成,而不是"必然"让任务更高效的完成,因为【并发】或多或少总会引入需要协作和沟通成本,如Java的线程模型,即多线程下的内核线程上下文切换的成本消耗以及共享资源锁的竞争等.

结束语

  【并行】和【并发】是两个完全不同的概念,一个是处理、一个是执行;理解好这两个概念,有助于提高我们的编程思维,在设计程序的时候,我们是不是可以把CPU密集型、网络IO、磁盘IO等任务类型拆开设计一个【并发】的方法,使CPU、网络IO、磁盘IO等资源更好的并行 ? 以Java的生态为例,从BIO到NIO甚至AIO、线程池(内核线程如阻塞IO调用时,操作系统会让出CPU执行权切换给其他线程调用)、Netty(经典的I/O多路复用思想)、Spring WebFlux、Vert.x、R2DBC等等技术.

相关参考资料


目录