概要:并发通常是提高运行在单处理器上的程序的性能。
“上面这句话听起来可能会违背直觉。如果你仔细考虑一下就会发现,在单处理器上运行的并发程序开销确实应该比该程序的所有部分都顺序执行的开销大,因为其中增加了上下文切换的代价(从一个任务切换到另一个任务)。表面上看,将程序的所有部分当作单个的任务运行好像是开销更小一点,并且可以节省上下文切换的代价。
这个问题变得有些不同的是阻塞。如果程序中的某个任务因为该程序控制范围之外的某些条件(通常是I/O)而导致不能继续执行,那么我们就说这个任务或线程阻塞了。如果没有并发,则整个程序都将停止下来,直至外部条件发生变化。但是,如果使用并发来编写程序,那么当一个任务阻塞时,程序中的其他任务还可以继续执行,因此这个程序可以保持继续向前执行。事实上,从性能的角度看,如果没有任务会阻塞,那么在单处理机器上使用并发就没有任何意义。” ——《Java编程思想》
比喻解析:
假设现在有5个人要拉屎(某个程序由多个子任务组成),5个人拉屎互不影响,不需要依赖别人(子任务各自独立)。现在卫生间只有一个坑位。(操作系统只有一个处理器,单处理器)。如果这5个人正常拉屎的时间分别是:5,5,5,5,5.
正常情况:
如果顺序执行,即按顺序一个一个拉的话,不出意外的情况下,这组人总的拉屎时间是25个单位时间。
如果并发执行,也就是每人每次只有1个单位时间(时间片)可以拉屎,过了时间就换人,这样可能频繁换人浪费了1.5个单位时间,那么这组人总的拉屎时间是27个单位时间。
这样看的话,并发并没有什么优势可言,反而由于频繁换人(上下文切换)浪费了时间。
异常情况:
但是,要考虑这样一种情况,即5个人中某个人肠胃不太好,很有可能会便秘(阻塞),这件事大家都知道(编程者知道,某个任务有可能会阻塞)
假设:这个肠胃不好的人是排在第二个,它要憋5单位时间,大便才能到位,然后正常排便需要花5单位时间。
如果顺序执行,那剩下的3个人只能干等着。那总拉屎时间可能是30个单位时间。
如果并发执行,这个便秘的拉不出来,1个单位时间到,就换人。但是这个人在外面依然可以酝酿,等待大便到位(大部分导致阻塞的原因是由于IO操作不到位,线程不占用处理器的时间里,可以继续进行IO操作。)。计算下来总的时间是27+1.5 = 28.5个单位时间。
这样的话,并发的优势就体现出来了。
注:拉屎只能进坑拉,酝酿在哪都能酝酿(计算操作只能在占用处理器的情况下进行,IO操作随时都可以)
存在问题:
1.这里案例阻塞时间的选择不太好。
2.比喻不恰当,现实中,不存在让人拉屎拉一半,让出坑位的说法。