试图从Linux内核的操作系统视图中回答它
程序在启动到内存时成为一个过程。进程有自己的地址空间,意味着在内存中有各种段,例如.text segement用于存储已编译的代码,.bss用于存储未初始化的静态或全局变量等。每个进程都有自己的程序计数器和用户spcae 堆 。在内核中,每个进程都有自己的内核堆栈(为了安全问题而与用户空间堆栈分开)和一个名为的结构 task_struct 通常将其抽象为过程控制块,存储关于过程的所有信息,例如其优先级,状态(以及许多其他块)。进程可以有多个执行线程。
task_struct
进入线程,它们驻留在进程内并共享父进程的地址空间以及可在线程创建期间传递的其他资源,例如文件系统资源,共享挂起信号,共享数据(变量和指令),从而使线程轻量级因此允许更快的上下文切换在内核中,每个线程都有自己的内核堆栈 task_struct 定义线程的结构。因此,内核查看与不同实体相同的进程的线程,并且可以自己调度。同一进程中的线程共享一个称为线程组id的公共ID( tgid ),他们也有一个唯一的id称为进程id( pid )。
tgid
pid
同一进程中的线程共享内存,但每个线程都有自己的堆栈和寄存器,线程在堆中存储特定于线程的数据。线程永远不会独立执行,因此与进程间通信相比,线程间通信要快得多。
进程永远不会共享相同的内存。子进程创建时,它会复制父进程的内存位置。通过使用管道,共享内存和消息解析来完成进程通信。线程之间的上下文切换非常慢。
应用程序由一个或多个进程组成。最简单的过程是一个执行程序。一个或多个线程在进程的上下文中运行。线程是操作系统分配处理器时间的基本单元。线程可以执行进程代码的任何部分,包括当前由另一个线程执行的部分。光纤是执行单元,必须由应用程序手动调度。光纤在调度它们的线程的上下文中运行。
被偷走了 这里 。
的 最佳答案 强>
的 处理: 强>
流程基本上是一个执行程序。它是一个活跃的实体。 某些操作系统使用术语“任务”来指代正在执行的程序。 进程始终存储在主存储器中,也称为主存储器或随机存取存储器。 因此,过程被称为活动实体。如果重新启动机器,它会消失。 几个过程可以与同一个程序相关联。 在多处理器系统上,可以并行执行多个进程。 在单处理器系统上,虽然没有实现真正的并行性,但是应用了进程调度算法,并且处理器被安排为一次执行一个进程,产生并发错觉。 示例:执行“计算器”程序的多个实例。每个实例都被称为一个过程。
的 线: 强>
线程是进程的子集。 它被称为“轻量级进程”,因为它类似于实际进程,但在进程的上下文中执行,并共享内核分配给进程的相同资源。 通常,进程只有一个控制线程 - 一次执行一组机器指令。 进程也可以由同时执行指令的多个执行线程组成。 多个控制线程可以利用多处理器系统上可能的真正并行性。 在单处理器系统上,应用线程调度算法,并且计划处理器一次运行一个线程。 进程内运行的所有线程共享相同的地址空间,文件描述符,堆栈和其他与进程相关的属性。 由于进程的线程共享相同的内存,因此使用该进程同步对共享数据的访问会获得前所未有的重要性。
参考 - https://practice.geeksforgeeks.org/problems/difference-between-process-and-thread
进程和线程之间的区别如下:
的 处理 强> :正在执行的程序称为进程
的 线 强> :Thread是一个功能,它与程序的其他部分一起执行,基于“one with other”的概念,因此线程是进程的一部分。
在使用包含多线程的Python(解释语言)构建算法时,我惊讶地发现,与我之前构建的顺序算法相比,执行时间并没有更好。为了理解这个结果的原因,我做了一些阅读,并相信我学到的东西提供了一个有趣的背景,从中可以更好地理解多线程和多进程之间的差异。
多核系统可以执行多个执行线程,因此Python应该支持多线程。但Python不是一种编译语言,而是一种解释语言 1 。这意味着必须解释程序才能运行,并且解释程序在开始执行之前不知道程序。然而,它所知道的是Python的规则,然后它动态地应用这些规则。然后,Python中的优化必须主要是解释器本身的优化,而不是要运行的代码。这与C ++等编译语言形成对比,并对Python中的多线程产生影响。具体来说,Python使用Global Interpreter Lock来管理多线程。
另一方面,编译语言已被编译。该程序“完全”处理,首先根据其语法定义进行解释,然后映射到语言不可知的中间表示,最后链接到可执行代码。此过程允许对代码进行高度优化,因为它在编译时全部可用。在创建可执行文件时定义各种程序交互和关系,并且可以做出关于优化的稳健决策。
在现代环境中,Python的解释器必须允许多线程,这必须既安全又有效。这就是解释语言与编译语言之间的区别。解释器不得干扰来自不同线程的内部共享数据,同时优化处理器的使用以进行计算。
正如之前的帖子中所指出的,进程和线程都是独立的顺序执行,主要区别在于内存在进程的多个线程之间共享,而进程隔离了它们的内存空间。
在Python中,全局解释器锁保护数据免受不同线程的同时访问。它要求在任何Python程序中,任何时候都只能执行一个线程。另一方面,可以运行多个进程,因为每个进程的内存与任何其他进程隔离,并且进程可以在多个核上运行。
1 Donald Knuth对“计算机编程艺术:基本算法”中的解释程序有很好的解释。
的 进程和线程的真实示例 强> 这将为您提供有关线程和进程的基本概念
我从Scott Langham的答案中借用了上述信息 - 谢谢
从访问者的角度来看,基本上只有3个主要内容我想听,除了明显的事情,比如一个进程可以有多个线程:
如果你想要更多,Scott Langham的回应几乎涵盖了一切。 所有这些都是从操作系统的角度出发的。不同的语言可以实现不同的概念,如任务,轻量级线程等,但它们只是使用线程(Windows上的光纤)的方式。 没有硬件和软件线程。有硬件和软件 的 例外 强> 和 的 中断 强> ,或用户模式和内核 的 线程 强> 。
示例1:JVM在单个进程中运行,JVM中的线程共享属于该进程的堆。这就是几个线程可以访问同一个对象的原因。线程共享堆并拥有自己的堆栈空间。这是一个线程调用方法及其局部变量的方式与其他线程保持线程安全的方式。但是堆不是线程安全的,必须同步才能保证线程安全。
进程和线程都是独立的执行序列。典型的区别在于(同一进程的)线程在共享内存空间中运行,而进程在不同的内存空间中运行。
处理
是一个正在执行的程序。它有文本部分,即程序代码,当前活动由程序计数器和值的值表示。处理器内容注册。它还包括包含临时数据(如函数参数,返回地址和局部变量)的进程堆栈,以及包含全局变量的数据部分。进程还可以包括堆,该堆是在进程运行时期间动态分配的内存。
线
线程是CPU利用率的基本单位;它包括线程ID,程序计数器,寄存器组和堆栈。它与属于同一进程的其他线程共享其代码段,数据段和其他操作系统资源,如打开文件和信号。
- 来自Galvin的操作系统
对于那些通过可视化学习更加舒适的人来说,这是我创建的用于解释过程和线程的方便图表。 我使用了MSDN的信息 - 关于进程和线程
它们几乎一样......但关键的区别在于线程是轻量级的,并且在上下文切换,工作负载等方面过程是重量级的。
来自嵌入式世界,我想补充说,流程的概念只存在于“大”处理器中( 台式机CPU,ARM Cortex A-9 )具有MMU(内存管理单元)和支持使用MMU的操作系统(如 Linux的 )。使用小/旧处理器和微控制器以及小型RTOS操作系统( 实时操作系统 ),例如freeRTOS,没有MMU支持,因此没有进程而只有线程。
的 主题 强> 可以访问彼此的内存,它们由操作系统以交错的方式进行调度,因此它们似乎并行运行(或者与多核并行运行)。
的 流程 强> 另一方面,他们住在MMU私人沙盒中,由MMU提供和保护。这很方便,因为它可以:
将流程视为所有权单位或任务所需的资源。进程可以拥有内存空间,特定输入/输出,特定文件和优先级等资源。
线程是可分派的执行单元,或者简单地说是通过一系列指令的进展
进程是代码,内存,数据和其他资源的集合。线程是在进程范围内执行的一系列代码。您(通常)可以在同一进程中同时执行多个线程。
我不确定你可能指的是什么“硬件”与“软件”线程。线程是一种操作环境功能,而不是CPU功能(尽管CPU通常具有使线程高效的操作)。
Erlang使用术语“进程”,因为它不公开共享内存多道程序模型。将它们称为“线程”意味着它们共享内存。
我借用了上面的信息 的 知识任务!博客 强> 。
首先,让我们看一下理论方面。您需要了解流程在概念上是什么来理解流程和线程之间的区别以及它们之间共享的内容。
我们从章节中得到以下内容 2.2.2经典线程模型 在 现代操作系统3e 作者:Tanenbaum:
流程模型基于两个独立的概念:资源 分组和执行。有时将它们分开是有用的; 这是线程进来的地方....
他继续:
查看流程的一种方法是它是一种方法 将相关资源集中在一起进程具有地址空间 包含程序文本和数据,以及其他资源。这些 资源可能包括打开的文件,子进程,待处理的警报, 信号处理程序,会计信息等。通过他们 以流程的形式,它们可以更容易地管理。 流程的另一个概念通常是执行的线程 缩短为只是线程。该线程有一个程序计数器保持 跟踪下一步执行的指令。它有寄存器,其中 保持当前的工作变量。它有一个堆栈,其中包含 执行历史记录,每个过程调用一帧但不调用 然而从...返回。虽然线程必须在某个进程中执行,但是 线程及其过程是不同的概念,可以处理 分开。流程用于将资源组合在一起;线程 是计划在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将支持单个执行线程,通过单个程序计数器和寄存器组维护线程的状态。但是如果有缓存未命中会发生什么?从主内存获取数据需要很长时间,而在发生这种情况时,CPU只是闲置在那里。所以有人有想法基本上有两组线程状态(PC +寄存器),这样另一个线程(可能在同一个进程中,可能在不同的进程中)可以在另一个线程在主内存上等待时完成工作。这个概念有多个名称和实现,例如HyperThreading和 同时多线程 (简称SMT)。
现在让我们来看看软件方面。在软件方面,线程基本上有三种实现方式。
实现线程所需要的只是能够保存CPU状态并维护多个堆栈,这在很多情况下可以在用户空间中完成。用户空间线程的优点是超快速的线程切换,因为您不必陷入内核并能够按照您喜欢的方式调度线程。最大的缺点是无法阻塞I / O(这会阻塞整个进程及其所有用户线程),这是我们首先使用线程的一个重要原因。在许多情况下,使用线程阻止I / O大大简化了程序设计。
除了将所有调度问题留给操作系统之外,内核线程还具有能够使用阻塞I / O的优点。但是每个线程切换都需要陷入内核,这可能相对较慢。但是,如果由于I / O阻塞而切换线程,这实际上不是问题,因为I / O操作可能已经将您困在内核中了。
另一种方法是将两者结合,多个内核线程各自具有多个用户线程。
回到你的术语问题,你可以看到一个过程和一个执行的线程是两个不同的概念,你选择使用哪个术语取决于你所谈论的内容。关于“轻量级过程”这个术语,我个人没有看到它的重点,因为它并没有真正传达正在发生的事情以及术语“执行线程”。
http://lkml.iu.edu/hypermail/linux/kernel/9608/0191.html
Linus Torvalds(torvalds@cs.helsinki.fi) 1996年8月6日星期二12:47:31 +0300(EET DST) 消息排序:[日期] [主题] [主题] [作者] 下一条消息:Bernd P. Ziller:“Re:在get_hash_table中哎呀” 上一条消息:Linus Torvalds:“Re:I / O请求订购” 1996年8月5日星期一,Peter P. Eiserloh写道: 我们需要明确线程的概念。太多人 似乎把一个线程与一个进程混淆了。以下讨论 不反映linux的当前状态,而是一个 试图保持高水平的讨论。 没有! 没有理由认为“线程”和“过程”是 单独的实体。这就是它传统上的做法,但我 个人认为这样思考是一个重大错误。唯一的 有理由认为这种方式是历史包袱。 线程和进程实际上只是一件事:一个“上下文” 执行“。试图人为地区分不同的情况 自限性。 “执行的背景”,在此称为COE,只是集团 该COE的所有状态。该状态包括CPU等 状态(寄存器等),MMU状态(页面映射),权限状态 (uid,gid)和各种“通信状态”(打开文件,信号 处理程序等)。传统上,“线程”和“线程”之间的区别 “进程”主要是线程有CPU状态(可能是+) 一些其他的最小状态),而所有其他的上下文来自 处理。但是,那只是 一 划分COE总状态的方法,并没有任何说明这是正确的方法。限制自己 这种形象只是愚蠢的。 Linux对此的看法(以及我希望工作的方式)是 那里 是 没有“过程”或“线程”这样的东西。有 只有COE的全部(Linux称为“任务”)。不同的COE 可以相互分享他们的上下文的一部分,一个 子集 的 共享是传统的“线程”/“进程”设置,但那 应该被视为仅仅是一个子集(它是一个重要的子集,但是 重要性不是来自设计,而是来自标准:我们很明智 想在Linux上运行符合标准的线程程序 太)。 简而言之:不要围绕线程/流程思维方式进行设计。该 内核应该围绕COE思维方式设计,然后再进行 并行线程 图书馆 可以将有限的pthreads接口导出给用户 谁想用这种看待COE的方式。 就像你认为COE那样可能的例子 反对线程/进程: 你可以做一个外部的“cd”程序,这在UNIX和/或进程/线程中是传统上不可能的(愚蠢的例子,但是这个想法) 是你可以拥有不限于此类的“模块” 传统的UNIX /线程设置)。做一个: 克隆(CLONE_VM | CLONE_FS); child:execve(“external-cd”); / *“execve()”将取消关联VM,这是我们唯一的原因 使用CLONE_VM是为了使克隆行为更快* / 你可以自然地做“vfork()”(它需要最小的内核支持,但这种支持完全符合CUA的思维方式): 克隆(CLONE_VM); 孩子:继续跑,最后execve() 妈妈:等待execve 你可以做外部“IO deamons”: 克隆(CLONE_FILES); child:打开文件描述符等 妈妈:用fd打开孩子和vv。 所有上述工作都是因为您没有与线程/进程绑定 思维方式。想象一下Web服务器,例如CGI 脚本作为“执行线程”完成。你不能这样做 传统线程,因为传统线程总是必须共享 整体地址空间,所以你必须链接你曾经的一切 想在Web服务器本身做(一个“线程”不能运行另一个 可执行文件)。 将此视为“执行环境”问题而非您的 任务现在可以选择执行外部程序(=分开 来自父母的地址空间)等等,如果他们想要,或者他们可以 示例与父级共享所有内容 除了 为文件 描述符(以便子“线程”可以打开许多文件而不用 父母需要担心他们:他们何时自动关闭 子“线程”退出,并且它不会在父级中使用fd。 例如,可以考虑使用线程化的“inetd”。你想要低开销 fork + exec,所以用Linux方式你可以代替使用“fork()” 你编写了一个多线程inetd,其中每个线程都是用它创建的 只是CLONE_VM(共享地址空间,但不共享文件描述符 等等)。如果是外部服务,孩子可以执行(rlogind, 例如),或者它可能是内部inetd服务之一 (echo,timeofday)在这种情况下它只是做它的事情并退出。 你不能用“线程”/“进程”来做到这一点。 莱纳斯
Linus Torvalds(torvalds@cs.helsinki.fi)
1996年8月6日星期二12:47:31 +0300(EET DST)
消息排序:[日期] [主题] [主题] [作者]
下一条消息:Bernd P. Ziller:“Re:在get_hash_table中哎呀”
上一条消息:Linus Torvalds:“Re:I / O请求订购”
1996年8月5日星期一,Peter P. Eiserloh写道:
我们需要明确线程的概念。太多人 似乎把一个线程与一个进程混淆了。以下讨论 不反映linux的当前状态,而是一个 试图保持高水平的讨论。
没有!
没有理由认为“线程”和“过程”是 单独的实体。这就是它传统上的做法,但我 个人认为这样思考是一个重大错误。唯一的 有理由认为这种方式是历史包袱。
线程和进程实际上只是一件事:一个“上下文” 执行“。试图人为地区分不同的情况 自限性。
“执行的背景”,在此称为COE,只是集团 该COE的所有状态。该状态包括CPU等 状态(寄存器等),MMU状态(页面映射),权限状态 (uid,gid)和各种“通信状态”(打开文件,信号 处理程序等)。传统上,“线程”和“线程”之间的区别 “进程”主要是线程有CPU状态(可能是+) 一些其他的最小状态),而所有其他的上下文来自 处理。但是,那只是 一 划分COE总状态的方法,并没有任何说明这是正确的方法。限制自己 这种形象只是愚蠢的。
Linux对此的看法(以及我希望工作的方式)是 那里 是 没有“过程”或“线程”这样的东西。有 只有COE的全部(Linux称为“任务”)。不同的COE 可以相互分享他们的上下文的一部分,一个 子集 的 共享是传统的“线程”/“进程”设置,但那 应该被视为仅仅是一个子集(它是一个重要的子集,但是 重要性不是来自设计,而是来自标准:我们很明智 想在Linux上运行符合标准的线程程序 太)。
简而言之:不要围绕线程/流程思维方式进行设计。该 内核应该围绕COE思维方式设计,然后再进行 并行线程 图书馆 可以将有限的pthreads接口导出给用户 谁想用这种看待COE的方式。
就像你认为COE那样可能的例子 反对线程/进程:
克隆(CLONE_VM | CLONE_FS);
child:execve(“external-cd”);
/ *“execve()”将取消关联VM,这是我们唯一的原因 使用CLONE_VM是为了使克隆行为更快* /
克隆(CLONE_VM);
孩子:继续跑,最后execve()
妈妈:等待execve
克隆(CLONE_FILES);
child:打开文件描述符等
妈妈:用fd打开孩子和vv。
所有上述工作都是因为您没有与线程/进程绑定 思维方式。想象一下Web服务器,例如CGI 脚本作为“执行线程”完成。你不能这样做 传统线程,因为传统线程总是必须共享 整体地址空间,所以你必须链接你曾经的一切 想在Web服务器本身做(一个“线程”不能运行另一个 可执行文件)。
将此视为“执行环境”问题而非您的 任务现在可以选择执行外部程序(=分开 来自父母的地址空间)等等,如果他们想要,或者他们可以 示例与父级共享所有内容 除了 为文件 描述符(以便子“线程”可以打开许多文件而不用 父母需要担心他们:他们何时自动关闭 子“线程”退出,并且它不会在父级中使用fd。
例如,可以考虑使用线程化的“inetd”。你想要低开销 fork + exec,所以用Linux方式你可以代替使用“fork()” 你编写了一个多线程inetd,其中每个线程都是用它创建的 只是CLONE_VM(共享地址空间,但不共享文件描述符 等等)。如果是外部服务,孩子可以执行(rlogind, 例如),或者它可能是内部inetd服务之一 (echo,timeofday)在这种情况下它只是做它的事情并退出。
你不能用“线程”/“进程”来做到这一点。
莱纳斯
解释有关并发编程的更多信息
进程具有自包含的执行环境。进程通常具有完整的私有基本运行时资源集;特别是,每个进程都有自己的内存空间。
线程存在于进程中 - 每个进程至少有一个进程。线程共享进程的资源,包括内存和打开文件。这使得有效但可能有问题的通信成为可能。
记住普通人,
在您的计算机上,打开Microsoft Word和Web浏览器。我们称之为这两个 流程 。
在Microsoft Word中,您键入一些内容并自动保存。现在,你会发现编辑和保存并行发生 - 在一个线程上编辑并保存在另一个线程上。