Linux中的线程与进程

问题描述 投票:230回答:14

我最近听过一些人说在Linux中,使用进程而不是线程几乎总是更好,因为Linux在处理进程方面非常有效,并且因为线程有很多问题(例如锁定)。但是,我很怀疑,因为在某些情况下,线程似乎可以带来相当大的性能提升。

所以我的问题是,当遇到线程和进程都能很好地处理的情况时,我应该使用进程还是线程?例如,如果我正在编写Web服务器,我应该使用进程或线程(或组合)吗?

linux performance multithreading process
14个回答
301
投票

Linux使用1-1线程模型,(对内核)没有进程和线程之间的区别 - 一切都只是一个可运行的任务。 *

在Linux上,系统调用clone克隆一个任务,具有可配置的共享级别,其中包括:

  • CLONE_FILES:共享相同的文件描述符表(而不是创建副本)
  • CLONE_PARENT:不要在新任务和旧任务之间建立父子关系(否则,孩子的getppid() =父母的getpid()
  • CLONE_VM:共享相同的内存空间(而不是创建COW副本)

fork()clone(least sharing)pthread_create()clone(most sharing)。 **

由于复制表并为内存创建COW映射,forking的成本比pthread_createing略高,但Linux内核开发人员已经尝试(并成功)降低了这些成本。

如果任务共享相同的内存空间和各种表,则在任务之间切换比不共享任务要便宜一点,因为数据可能已经加载到缓存中。但是,即使没有共享任何内容,切换任务仍然非常快 - 这是Linux内核开发人员试图确保(并成功确保)的其他内容。

实际上,如果您使用的是多处理器系统,则不共享可能实际上对性能有益:如果每个任务在不同的处理器上运行,则同步共享内存非常昂贵。


*简化。 CLONE_THREAD导致信号传递被共享(需要CLONE_SIGHAND,它共享信号处理程序表)。

**简化。存在SYS_forkSYS_clone系统调用,但在内核中,sys_forksys_clone都是围绕相同的do_fork函数的非常薄的包装器,它本身是围绕copy_process的薄包装器。是的,术语processthreadtask在Linux内核中可以互换使用......


3
投票

在我最近使用LINUX的工作中,有一点需要注意的是库。如果您正在使用线程,请确保您可以跨线程使用的任何库都是线程安全的。这烧了我几次。值得注意的是,libxml2不是开箱即用的线程安全的。它可以使用线程安全编译,但这不是aptitude安装所能获得的。


2
投票

对于大多数情况,我更喜欢进程而不是线程。当您具有相对较小的任务(进程开销>>每个划分的任务单元所花费的时间)并且它们之间需要内存共享时,线程可能很有用。想一个大阵列。另外(offtopic),请注意,如果您的CPU利用率是100%或接近它,那么多线程或处理将没有任何好处。 (事实上​​它会恶化)


1
投票

线程 - >线程共享一个内存空间,它是CPU的抽象,它是轻量级的。进程 - >进程有自己的内存空间,它是计算机的抽象。要并行化任务,您需要抽象CPU。然而,在线程上使用进程的优点是安全性,稳定性,而线程使用的内存比进程少,并且提供较少的延迟。关于web的一个例子是chrome和firefox。在Chrome的情况下,每个选项卡都是一个新进程,因此chrome的内存使用率高于firefox,而提供的安全性和稳定性优于firefox。 chrome提供的安全性更好,因为每个选项卡都是一个新进程,不同的选项卡不能窥探到给定进程的内存空间。


1
投票

我想每个人都能很好地回答你的问题。我只是在Linux中添加有关线程与进程的更多信息,以澄清和总结内核上的一些先前的响应。所以,我的回答是关于Linux中的内核特定代码。根据Linux内核文档,线程与进程之间没有明显区别,除了线程使用共享虚拟地址空间与进程不同。另请注意,Linux内核使用术语“任务”来指代进程和线程。

“没有内部结构实现进程或线程,而是有一个struct task_struct描述一个名为task的抽象调度单元”

同样根据Linus Torvalds,你根本不应该考虑进程与线程,因为它太限制了,唯一的区别是COE或执行语境在“将地址空间与父级分开”或共享地址空间方面。事实上,他使用一个Web服务器示例来表达他的观点here(强烈推荐阅读)。

完全归功于linux kernel documentation


-2
投票

如果你需要共享资源,你真的应该使用线程。

还要考虑这样一个事实,即线程之间的上下文切换比进程之间的上下文切换便宜得多。

除非你有充分的理由这样做(安全性,经过验证的性能测试等等),否则我认为没有理由明确采用单独的流程。


57
投票

Linux(实际上是Unix)为您提供了第三种选择。

Option 1 - processes

创建一个独立的可执行文件来处理应用程序的某些部分(或所有部分),并为每个进程单独调用它,例如:程序运行自身的副本以将任务委派给。

Option 2 - threads

创建一个独立的可执行文件,它以单个线程启动并创建其他线程来执行某些任务

Option 3 - fork

仅在Linux / Unix下可用,这有点不同。分叉进程实际上是它自己的进程,它有自己的地址空间 - 孩子可以(通常)不会影响其父进程或兄弟地址空间(与线程不同) - 所以你可以增加健壮性。

但是,内存页面不会被复制,它们是写时复制的,因此通常使用的内存比您想象的要少。

考虑一个Web服务器程序,它包含两个步骤:

  1. 读取配置和运行时数据
  2. 提供页面请求

如果您使用了线程,则步骤1将完成一次,而步骤2将在多个线程中完成。如果使用“传统”进程,则需要为每个进程重复步骤1和2,并且存储配置和运行时数据的内存重复。如果您使用了fork(),那么您可以执行第1步,然后执行fork(),将运行时数据和配置保留在内存中,不受影响,不进行复制。

所以真的有三种选择。


50
投票

这取决于很多因素。进程比线程更重,并且具有更高的启动和关闭成本。进程间通信(IPC)也比线程通信更难,更慢。

相反,进程比线程更安全,更安全,因为每个进程都在自己的虚拟地址空间中运行。如果一个进程崩溃或缓冲区溢出,它根本不会影响任何其他进程,而如果一个线程崩溃,它将关闭进程中的所有其他线程,如果一个线程有缓冲区溢出,它会打开所有线程中的安全漏洞。

因此,如果您的应用程序的模块可以在几乎没有通信的情况下独立运行,那么如果您能够承担启动和关闭成本,则应该使用流程。 IPC的性能影响将是最小的,您将对错误和安全漏洞稍微安全一些。如果您需要每一点性能,您可以获得或拥有大量共享数据(例如复杂的数据结构),请使用线程。


10
投票

其他人讨论了这些考虑因素

也许重要的区别在于,与线程相比,Windows进程繁重且昂贵,而在Linux中,差异要小得多,因此方程式在不同点进行平衡。


8
投票

曾几何时有Unix,在这个老的Unix中有很多进程的开销,所以一些聪明的人做的是创建线程,它将与父进程共享相同的地址空间,他们只需要减少上下文切换,这将使上下文切换更有效。

在当代Linux(2.6.x)中,进程的上下文切换与线程之间的性能差别不大(只有MMU的东西是线程的附加内容)。共享地址空间存在问题,这意味着线程中的错误指针可能破坏父进程的内存或同一地址空间内的另一个线程。

进程受MMU保护,因此错误的指针只会导致信号11而不会损坏。

我一般会使用进程(在Linux中没有太多的上下文切换开销,但由于MMU导致内存保护),但如果我需要一个实时的调度程序类,那就是pthreads,这是一个不同的茶。

为什么你认为线程在Linux上有如此大的性能提升?你有这方面的数据,还是只是一个神话?


5
投票

你的任务有多紧密耦合?

如果他们可以彼此独立生活,那么使用流程。如果他们互相依赖,那就使用线程。这样,您可以在不干扰其他任务的操作的情况下终止并重启坏的进程。


4
投票

更复杂的是,有thread-local storage和Unix共享内存这样的东西。

线程局部存储允许每个线程具有单独的全局对象实例。我唯一一次使用它是在linux / windows上构建仿真环境,用于在RTOS中运行的应用程序代码。在RTOS中,每个任务都是一个具有自己地址空间的进程,在仿真环境中,每个任务都是一个线程(具有共享地址空间)。通过将TLS用于单例等事物,我们能够为每个线程创建一个单独的实例,就像在“真正的”RTOS环境下一样。

共享内存可以(显然)为您提供多个进程访问相同内存的性能优势,但代价是成本/风险必须正确同步进程。一种方法是让一个进程在共享内存中创建数据结构,然后通过传统的进程间通信(如命名管道)向该结构发送句柄。


3
投票

我必须同意你听到的内容。当我们对我们的集群(xhpl等)进行基准测试时,我们总是通过线程获得更好的性能。 </anecdote>


3
投票

线程/进程之间的决定取决于您将使用它的内容。进程的一个好处是它具有PID并且可以在不终止父进程的情况下被终止。

对于Web服务器的真实示例,apache 1.3过去只支持多个进程,但在2.0中,他们添加了an abstraction,以便您可以在两者之间切换。 Comments seems to同意进程更强大,但线程可以提供更好的性能(除了窗口,其中进程的性能很糟糕而你只想使用线程)。

© www.soinside.com 2019 - 2024. All rights reserved.