进程和线程之间的技术区别是什么?

我感觉像“进程”这样的词被过度使用了,而且还有硬件和软件线程。像Erlang这样的语言中的轻量级进程怎么样?是否有明确的理由使用一个术语而不是另一个术语?


当前回答

首先,让我们看看理论方面。您需要从概念上理解什么是进程,才能理解进程和线程之间的区别以及它们之间的共享。

Tanenbaum在第2.2.2节现代操作系统的经典线程模型3e中介绍了以下内容:

流程模型基于两个独立的概念:资源分组和执行。有时将它们分开是有用的;这是线程进入的地方。。。。

他继续说道:

看待过程的一种方式是将相关资源分组在一起。进程具有地址空间包含程序文本和数据以及其他资源。这些资源可以包括打开的文件、子进程、挂起的警报等,信号处理器、会计信息等。通过将它们以流程的形式结合在一起,可以更容易地管理它们。进程的另一个概念是执行线程,通常缩短为仅螺纹。线程有一个程序计数器跟踪下一步要执行的指令。它有寄存器保持其当前工作变量。它有一个堆栈,其中包含执行历史,每个过程调用一帧,但未调用但从返回。尽管线程必须在某些进程中执行线程及其进程是不同的概念分别地。流程用于将资源分组在一起;螺纹是计划在CPU上执行的实体。

接下来,他提供了下表:

Per process items             | Per thread items
------------------------------|-----------------
Address space                 | Program counter
Global variables              | Registers
Open files                    | Stack
Child processes               | State
Pending alarms                |
Signals and signal handlers   |
Accounting information        |

让我们来处理硬件多线程问题。传统上,CPU将支持单个执行线程,通过单个程序计数器(PC)和一组寄存器来维护线程的状态。但当缓存未命中时会发生什么?从主内存中获取数据需要很长时间,而当这发生时,CPU只是闲置在那里。所以有人想到了基本上有两组线程状态(PC+寄存器),这样另一个线程(可能在同一个进程中,也可能在不同的进程中)就可以在其他线程等待主内存时完成工作。这个概念有多种名称和实现,例如超线程和同时多线程(简称SMT)。

现在让我们看看软件方面。基本上有三种方法可以在软件端实现线程。

用户空间线程内核进程两者的结合

实现线程所需要的是保存CPU状态和维护多个堆栈的能力,这在许多情况下可以在用户空间中完成。用户空间线程的优点是超快速的线程切换,因为您不必陷入内核,也不必按照自己喜欢的方式调度线程。最大的缺点是无法阻止I/O(这会阻止整个进程及其所有用户线程),这是我们首先使用线程的主要原因之一。在许多情况下,使用线程阻止I/O大大简化了程序设计。

除了将所有调度问题留给操作系统之外,内核线程还具有能够使用阻塞I/O的优点。但每个线程切换都需要捕获内核,这可能会相对较慢。然而,如果由于I/O阻塞而切换线程,这实际上不是问题,因为I/O操作可能已经将您困在内核中。

另一种方法是将两者结合起来,多个内核线程每个都有多个用户线程。

因此,回到术语问题,您可以看到流程和执行线程是两个不同的概念,您选择使用哪个术语取决于您所谈论的内容。关于“轻量级过程”这一术语,我个人看不出其中的意义,因为它并没有像“执行线程”这一词那样真正传达出正在发生的事情。

其他回答

在用Python(解释语言)构建包含多线程的算法时,我惊讶地发现,与我之前构建的顺序算法相比,执行时间并没有任何改善。为了理解导致这种结果的原因,我做了一些阅读,并相信我所学到的内容提供了一个有趣的背景,可以更好地理解多线程和多进程之间的差异。

多核系统可能会执行多个线程,因此Python应该支持多线程。但Python不是一种编译语言,而是一种解释语言1。这意味着必须对程序进行解释才能运行,并且在程序开始执行之前,解释器不知道程序。然而,它所知道的是Python的规则,然后动态地应用这些规则。Python中的优化必须主要是解释器本身的优化,而不是要运行的代码。这与C++等编译语言形成对比,并对Python中的多线程产生影响。具体来说,Python使用全局解释器锁来管理多线程。

另一方面,编译语言是编译的。程序被“完全”处理,首先根据其语法定义进行解释,然后映射到语言不可知的中间表示,最后链接到可执行代码中。这个过程允许代码得到高度优化,因为在编译时所有代码都可用。在创建可执行文件时定义了各种程序交互和关系,可以做出关于优化的稳健决策。

在现代环境中,Python的解释器必须允许多线程,这必须既安全又高效。这就是解释语言与编译语言的区别所在。解释器必须不干扰来自不同线程的内部共享数据,同时优化处理器的计算使用。

如前几篇文章所述,进程和线程都是独立的顺序执行,主要区别在于内存在进程的多个线程之间共享,而进程隔离了它们的内存空间。

在Python中,全局解释器锁防止不同线程同时访问数据。它要求在任何Python程序中,任何时候只能执行一个线程。另一方面,可以运行多个进程,因为每个进程的内存都与任何其他进程隔离,并且进程可以在多个内核上运行。


唐纳德·克努思在《计算机编程的艺术:基本算法》中对解释例程有很好的解释。

进程和线程都是独立的执行序列。典型的区别是(同一进程的)线程在共享内存空间中运行,而进程在单独的内存空间中。

过程

是一个正在执行的程序。它具有文本部分,即程序代码、当前活动(由程序计数器的值和处理器寄存器的内容表示)。它还包括包含临时数据(如函数参数、返回地址和局部变量)的进程堆栈和包含全局变量的数据部分。进程还可以包括堆,堆是在进程运行时动态分配的内存。

线

线程是CPU利用率的基本单位;它包括线程ID、程序计数器、寄存器集和堆栈。它与属于同一进程的其他线程共享其代码部分、数据部分和其他操作系统资源,例如打开的文件和信号。

--摘自Galvin的操作系统

此信息可在Microsoft了解此处:关于进程和线程

过程每个进程提供执行程序所需的资源。进程具有虚拟地址空间、可执行代码、系统对象的开放句柄、安全上下文、唯一进程标识符、环境变量、优先级类、最小和最大工作集大小以及至少一个执行线程。每个进程都由一个线程启动,通常称为主线程,但可以从其任何线程创建其他线程。线线程是进程中的一个实体,可以被安排执行。进程的所有线程共享其虚拟地址空间和系统资源。此外,每个线程都维护异常处理程序、调度优先级、线程本地存储、唯一的线程标识符以及系统将用于保存线程上下文的一组结构,直到它被调度。线程上下文包括线程的一组机器寄存器、内核堆栈、线程环境块和线程进程地址空间中的用户堆栈。线程也可以有自己的安全上下文,可用于模拟客户端。Microsoft Windows支持抢占式多任务处理,这会产生多个进程同时执行多个线程的效果。在多处理器计算机上,系统可以同时执行计算机上处理器的数量。

进程和线程都是独立的执行序列。典型的区别是(同一进程的)线程在共享内存空间中运行,而进程在单独的内存空间中。

我不确定你可能指的是什么“硬件”线程和“软件”线程。线程是一种操作环境特性,而不是CPU特性(尽管CPU通常具有使线程高效的操作)。

Erlang使用术语“进程”,因为它不公开共享内存多道程序模型。称它们为“线程”意味着它们共享内存。

对于那些更喜欢通过可视化学习的人来说,这里是我创建的一个方便的图表,用于解释流程和线程。我使用了MSDN中的信息-关于进程和线程