深入并发编程(一)基础理论
作者: Tivon(一只有拖延症的female程序猿)
参考资料:
首发CSDN。转载请注明出处。
前言
随着做开发的时间越来越长,接触的东西多了之后。就会发现脑子是越来越不够用了,编写本系列博客的初衷也是这样,单纯用于记录我学习并发的过程。
并发
何谓并发
要理解并发,首先要区别并发(concurrency)与并行(parallellism)。
并行:多个任务同时执行。
并发:多个任务看起来同时执行。
我们来举个栗子:
在单核CPU的情况下:假设按摩店里只有一个小妹(CPU)
这个时候你和你的同事两个人同时去按摩店里按摩。 按摩小妹的速度非常快,在你和你的同事之间来回切换,由于小妹的速度很快,你和你的同事觉得仿佛有两个小妹在同时给你们做按摩。
没有错,这种情况就是并发。
你和你的同时感觉有两个小妹在同时给你们按摩。但是实际上只有一个小妹(CPU)。
而并行的话很容易理解:你和你的同时去按摩店,按摩店里有两个小妹,同时的给你们两个人按摩。
这两个例子里面都出现了“同时”这个关键词,区别在于:
并行:是真正物理上的同时(有两个小妹)。
并发:看起来是同时的(只有一个小妹)。
为什么要使用并发
在理解了并发的意思之后,我们需要明确我们为什么需要让我们的程序并发执行,并发的好处是什么,或者说,在什么情况下我们是需要并发的。
首先:我们进行并发编程的目的,是为了充分的利用处理器的每一个核,以达到最高的处理性能。
针对这个结论,我们又有了新的问题:
让程序变成并发,一定可以提高处理性能吗?
通过我们上面按摩的例子,大家可以知道,在单核CPU(一个按摩小妹)的情况下,运行一个多线程的程序,同一时间只有一个线程被执行(同一时间按摩小妹只能按摩一个人),只是因为CPU的速度很快,所以多线程看起来是同时在执行的。
这个时候,CPU的速度是固定的,但是要执行的任务变成了多个,那么以时间角度来说,CPU执行完一个任务再执行另一个任务(串行执行)所要花费的时间比并发执行多个任务花费的时间要少。 这是因为CPU在并发执行多个任务的时候,同一时刻是只能执行一个线程的,那么多个线程之间切换的过程也会增加时间的开销。
所以:在单核CPU的情况下,并发并不一定能提升性能,反而会因为线程之间的切换而造成额外的开销。
但是要注意这个结论中加粗的“并不一定”几个字。 我们还需要分析这样的情况:
在单核CPU的情况下:
只有一个按摩小妹给你一个人在按摩,这个时候你来电话了,或者有其他的事情导致你必须中断你的按摩(线程阻塞),那么这个时候按摩小妹就会处于一种无事可做的状态,一直阻塞到你可以重新回来被按摩为止。
而这一段空闲时间,按摩小妹完全可以去按摩其他人(执行其他线程)。
由此我们可以得出结论:
在单核CPU,且线程无阻塞的情况下:单线程执行效率要比多线程高。
什么时候适合做并发编程
无论使用什么技术,我们都有一个统一原则:
如果:付出>收益,那么就不适合。与之相反,如果:付出<收益,就是适合的。
并发编程也是一样的,我们在使用多线程技术进行并发编程的时候,一定要考虑:
增加线程所带来的额外开销是否大于该线程能抵消的阻塞时间?
也就是说:线程并不是越多越好的,多线程技术的出现是为了弥补线程的阻塞导致的线程资源浪费以及多核CPU下任务的并行(注意不是并发)执行问题。
而并发编程只是多线程技术的一个部分。
多线程解决了并发和并行的问题。
N核CPU同时执行N个任务叫做并行。
N核CPU执行N+个任务叫做并发。
那么我们什么时候使用并发合适呢?
在线程存在任务阻塞的时候,且并发所带来的线程切换开销小于阻塞时间。
本章小结
- 并发和并行的区别
- 并发并不一定能提高效率,让任务并发执行时,一定要考虑线程并发所带来的额外开销(线程切换)是否小于线程阻塞的时间开销。
- 多线程≠并发,多线程技术是实现并发和并行的一种方式。只有开辟多于CPU核数的线程任务才叫做并发编程。