面试必问问题之多进程与多线程的区别(超详细)

要想了解什么是多进程和多线程,首先要明白为什么会出现进程和线程,下面我会一步步进行说明。

为什么要引入进程

学过操作系统的应该会知道,多道程序设计的特点是多道,宏观上并行,微观上串行,而引入多道批处理系统就是为了提高系统资源的利用率,尽量使cpu处于繁忙状态,使各种资源能够得到充分利用,那么这样会出现什么情况呢?在多道程序同时运行的环境下,允许多个程序并发执行,此时他们将失去封闭性,并具有间断性及不可再现性的特征,程序本身是一组执行特定功能的指令的集合,是一个静态的概念,无法描述程序在内存中何时执行,何时停顿,也无法看出它与其它执行程序的关系,因此,程序这个静态的概念已不能如实反映程序并发执行过程的特征,为了能够更好的描述和控制程序的并发执行,实现操作系统的并发性和共享性,我们引入了进程这一概念。
为了更好的理解进程,需要明白并发和并行的区别。
并发是指两个或多个事件在同一时间间隔内发生,比如早上8:00-9:00这一时间间隔内你先洗漱然后再吃饭就是指的吃饭和洗漱这两个事件并发,但是为什么说多道程序设计下是微观上并行呢,可以这么理解,操作系统把这一时间间隔看成了一个时刻,那么在这一时刻,操作系统只知道你干完了吃饭和洗漱这两件事,并且操作系统是通过分时来实现并发的。
并行是指在同一时刻完成两种或者以上的工作,需要硬件的支持,比如早上8:00-9:00这一时间间隔内你一边玩手机,一边吃饭,那么这两个事件就是并行。通俗点理解就是并发是指两个事件或多个事件有先后顺序的执行,而并行是指两个事件或多个事件同时进行的。

什么是多进程

多进程就是指计算机同时执行多个进程,一般是同时运行多个软件。前面提到了引入进程就是为了能够更好的描述程序的并发执行,可想而知,进程是与资源有关的,所以进程就是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位。进程实体是由程序段,相关数据段和PCB组成,而PCB是进程控制块,是为了使参与并发执行的程序能独立运行而专门配置的一个数据结构,注意PCB是进程存在的唯一标志。进程有用户进程和系统进程之分,其中凡是用于完成操作系统的各种功能的进程就是系统进程,而所有由用户启动的进程都是用户进程。

为什么要引入线程

前面提到过进程是与资源有关的,而进程又是动态的,因此进程进行切换时需要占用系统较多的开销,影响了系统的并发性能,那么有没有什么办法可以尽量的降低系统开销呢,于是引入了线程,尽量减小程序在并发执行时所付出的时空开销,提高操作系统的并发性能。

什么是多线程

多线程就是指一个进程中同时有多个线程正在执行
线程是一个基本的cpu执行单元,是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,可以与同属于一个进程的其他线程共享进程所拥有的全部资源。引入线程之后,进程只作为除cpu以外系统资源的分配单元,线程则作为处理机的分配单元。
线程的实现可以分为用户级线程和内核级线程,在用户级线程中,有关线程管理的所有工作都有应用程序完成,内核意识不到线程的存在。在内核级线程中,线程管理的所有工作都是内核完成,应用程序无权管理线程。因此可以理解为多线程是一种执行模型,包括多对一模型,一对一模型,多对多模型。
多对一模型:将多个用户级线程映射到一个内核级线程,线程管理在用户空间完成。
优点:线程管理是在用户空间进行的,对于线程的管理不涉及内核的服务,因此效率比较高。
缺点:由于用户级线程对操作系统不可见,即多个用户级线程实际上操作系统只会认为其只有一个用户级线程,当一个用户级线程在使用内核服务时被阻塞,那么整个进程都会被阻塞,即其他的用户级线程也不能运行了。另外,此模式下,多个线程不能并行地运行在多处理机上。
一对一模型:将每个用户级线程映射到一个内核级线程。
优点:当一个线程被阻塞时,允许另一个线程继续执行,所以并发性能较强。
缺点:每创建一个用户级线程都需要创建一个内核级线程,这样导致了创建线程的开销较大,会影响程序的性能。
多对多模型:将n个用户级线程映射到m个内核级线程,要求m<=n。
特点:是前两种模型的折中,即克服了多对一模型的并发度不高的缺点,也克服了一对一模型的开销太大的缺点。

进程和线程的比较

引入线程之后,线程是独立调度的基本单位,进程是拥有资源的基本单位,不仅进程之间可以并发执行,并且线程之间也可以并发执行,使得操作系统具有更好的并发性,因为线程不拥有系统资源故使用线程调度时系统开销小。

多进程和多线程应该如何选择

下面是我在知乎-pansz上转载的一个答案,非常通俗地回答了这个问题。

单进程单线程:一个人在一个桌子上吃菜。
单进程多线程:多个人在同一个桌子上一起吃菜。
多进程单线程:多个人每个人在自己的桌子上吃菜。

多线程的问题是多个人同时吃一道菜的时候容易发生争抢,例如两个人同时夹一个菜,一个人刚伸出筷子,结果伸到的时候已经被夹走菜了。。。此时就必须等一个人夹一口之后,在还给另外一个人夹菜,也就是说资源共享就会发生冲突争抢。
1。对于 Windows 系统来说,【开桌子】的开销很大,因此 Windows 鼓励大家在一个桌子上吃菜。因此 Windows 多线程学习重点是要大量面对资源争抢与同步方面的问题。
2。对于 Linux 系统来说,【开桌子】的开销很小,因此 Linux 鼓励大家尽量每个人都开自己的桌子吃菜。这带来新的问题是:坐在两张不同的桌子上,说话不方便。因此,Linux 下的学习重点大家要学习进程间通讯的方法。
开桌子的意思是指创建进程。开销这里主要指的是时间开销。
可以做个实验:创建一个进程,在进程中往内存写若干数据,然后读出该数据,然后退出。此过程重复 1000 次,相当于创建/销毁进程 1000 次。在我机器上的测试结果是:
UbuntuLinux:耗时 0.8 秒
Windows7:耗时 79.8 秒
两者开销大约相差一百倍。
这意味着,在 Windows 中,进程创建的开销不容忽视。换句话说就是,Windows 编程中不建议你创建进程,如果你的程序架构需要大量创建进程,那么最好是切换到 Linux 系统。
大量创建进程的典型例子有两个,一个是 gnu autotools 工具链,用于编译很多开源代码的,他们在 Windows 下编译速度会很慢,因此软件开发人员最好是避免使用 Windows。另一个是服务器,某些服务器框架依靠大量创建进程来干活,甚至是对每个用户请求就创建一个进程,这些服务器在 Windows 下运行的效率就会很差。这"可能"也是放眼全世界范围,Linux 服务器远远多于 Windows 服务器的原因。
再次补充:如果你是写服务器端应用的,其实在现在的网络服务模型下,开桌子的开销是可以忽略不计的,因为现在一般流行的是按照 CPU 核心数量开进程或者线程,开完之后在数量上一直保持,进程与线程内部使用协程或者异步通信来处理多个并发连接,因而开进程与开线程的开销可以忽略了。
另外一种新的开销被提上日程:核心切换开销。
现代的体系,一般 CPU 会有多个核心,而多个核心可以同时运行多个不同的线程或者进程。当每个 CPU 核心运行一个进程的时候,由于每个进程的资源都独立,所以 CPU 核心之间切换的时候无需考虑上下文。
当每个 CPU 核心运行一个线程的时候,由于每个线程需要共享资源,所以这些资源必须从 CPU 的一个核心被复制到另外一个核心,才能继续运算,这占用了额外的开销。换句话说,在 CPU 为多核的情况下,多线程在性能上不如多进程。
因而,当前面向多核的服务器端编程中,需要习惯多进程而非多线程。

本人水平有限,可能总结不到位,欢迎各位评论指点!

你可能感兴趣的:(计算机专业面试问题总结)