1、简述进程和线程
进程:
1)操作系统进行资源分配(内存、磁盘、显卡)的基本单位,多个进程之间相互独立(地址空间和数据空间),需要通信的话是在操作系统层面进行通信
2)稳定性好,如果一个进程崩溃,不影响其他进程,但是进程消耗资源大,开启的进程数量有限制
线程:
1)CPU进行资源分配和调度的基本单位(CPU看到的都是线程不是进程),线程是进程的一部分,是比进程更小的能够独立运行的基本单位,一个进程下的多个线程可以共享该进程的所有资源(地址空间和数据空间),一个线程的数据可以直接提供给其他线程使用,比较方便,但同时会造成变量值的混乱,所以需要通过线程锁来限制线程的执行
2)如果IO操作密集,则可以多线程运行效率高,缺点就是如果一个线程崩溃,就会造成进程的崩溃
应用场景:
1)IO密集的用多线程,在用户输入,sleep的时候,可以切换到其他线程执行,减少等待的时间
2)CPU密集的用多进程,因为假如IO操作较少,用多线程的话,因为线程共享一个全局解释器锁,当前运行的线程会霸占GIL,导致其他线程没有GIL,就不能充分利用多核CPU的优势
2、CPU密集型和IO密集型
CPU密集型:
指的是大部分的状况下是CPU Loading 100%,CPU要读写I/O(硬盘/内存),I/O在很短的时间内就可以完成,而CPU还有很多运算要处理,整个过程中系统的硬盘、内存性能相对CPU要好很多
例如:算法里面的模型运算工作,如一个计算圆周率至小数点一千位以下的程序,在执行的过程当中绝大部份时间用在三角函数和开根号的计算,属于CPU密集型的程序,全靠CPU的运算能力。这种计算密集型任务虽然可以用多线程完成,但是线程越多,花在线程切换的时间就越多,CPU执行任务的效率就越低,所以,要高效地利用CPU,CPU密集型任务同时运行的线程数量应当等于CPU的核数,这样可以占满CPU资源,进而充分利用CPU
IO密集型:
指的是大部分的状况下是CPU在等I/O(硬盘/内存)的读写操作,此时的CPU Loading并不高,整个过程中系统的CPU性能相对硬盘、内存要好很多
例如:读写数据库等,CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度),对于IO密集型任务,线程越多,CPU效率越高,但也要有一个限度,常见的大部分任务都是IO密集型任务
IO密集型任务执行期间,99%的时间都花在IO上,花在CPU上的时间很少,因为,用运行速度极快的C语言替换Python这样运行速度极低的脚本语言,完全无法提升运行效率,对于IO密集型任务,最合适的语言就是开发效率高(代码量少)的语言,脚本语言是首选,C语言最差
IO密集型任务线程由于等待IO会被阻塞,如果仍然使用等于 CPU核数 个线程,CPU是跑不满的,需要使用更多线程来提高CPU利用率
总之,CPU密集型程序适合C语言多线程,IO密集型的适合脚本语言开发的多线程
3、多核、多进程、多线程
计算机的物理核数是同时可以并行的线程数量(CPU看到的都是线程,线程是CPU调度分配的最小单位),由于超线程技术(一个实体CPU提供两个逻辑线程),实际上可以并行的线程数量通常是物理核数的两倍,这也是操作系统看到的核数,所以我们说的核数是操作系统看到的核数,指的是超线程技术之后的那个核(不是物理核)
如果计算机有多个CPU核,且计算机中总的线程数量小于核数,那线程可以运行在不同的核中。
如果是单核多线程,那么多线程之间就不是并行,而是并发,即为了负载均衡CPU调度器会不断在单核上切换不同的线程执行,但是我们说过,一个核只能运行一个线程,所以并发虽然让我们看起来不同线程之间的任务是并行执行的,但实际上因为增加了线程切换的开销使得代价更大了。
如果是多核多线程,且线程数量大于核数,其中有些线程就会不断切换,并发执行,但实际上最大的并行数量还是CPU的核的数量。
4、linux中最大进程数、最大线程数
最大进程数
(1)32位系统中最多可以起32768个进程
(2)64位系统中最多可以起2的22次方(4194304)约420万个
[root@**** ~]$ cat /proc/sys/kernel/pid_max
32768
最大线程数
其实最大线程数量也可以配置无限大,在资源充足的情况下,但一般都有会默认限制
[root@**** ~]$ cat /proc/sys/kernel/threads-max
1543275
正常情况下,系统默认的配置已经足够我们使用,除非想进行一些极限性能测试或者性能优化,这时候可以根据具体的情况来调整上面提到的几个参数
5、python语言特殊性
CPU是多核时支持多个线程同时执行,但在python中,无论是单核还是多核,一个进程同时只能由一个线程在执行。根源在于GIL的存在,GIL全称是Global Interpreter Lock(全局解释锁),来源是python设计之初的考虑,为了数据安全所做的决定,某个线程想要执行,必须先拿到 GIL,我们可以把 GIL 看作是“通行证”,并且在一个 Python 进程中,GIL 只有一个,拿不到通行证的线程,就不允许进入 CPU 执行,所以多线程在python中很鸡肋,多线程的运行顺序仍是有先后的,并不是同时进行的。
网友评论