use*_*918 244 linux performance multithreading process
我最近听过一些人说在Linux中,使用进程而不是线程几乎总是更好,因为Linux在处理进程方面非常有效,并且因为线程有很多问题(例如锁定).但是,我很怀疑,因为在某些情况下,线程似乎可以带来相当大的性能提升.
所以我的问题是,当遇到线程和进程都能很好地处理的情况时,我应该使用进程还是线程?例如,如果我正在编写Web服务器,我应该使用进程或线程(或组合)吗?
eph*_*ent 311
Linux使用1-1线程模型,(对内核)没有进程和线程之间的区别 - 一切都只是一个可运行的任务.*
在Linux上,系统调用clone克隆任务,具有可配置的共享级别,其中包括:
CLONE_FILES:共享相同的文件描述符表(而不是创建副本)CLONE_PARENT:不要在新任务和旧任务之间建立父子关系(否则,孩子的getppid()=父母的getpid())CLONE_VM:共享相同的内存空间(而不是创建COW副本)fork()呼叫clone(最少共享)和pthread_create()呼叫clone(大多数共享).**
forkpthread_create由于复制表和为内存创建COW映射,成本只是一点点,但Linux内核开发人员已经尝试(并成功)降低了这些成本.
如果任务共享相同的内存空间和各种表,则在任务之间切换比不共享任务要便宜一点,因为数据可能已经加载到缓存中.但是,即使没有共享任何内容,切换任务仍然非常快 - 这是Linux内核开发人员试图确保(并成功确保)的其他内容.
实际上,如果您使用的是多处理器系统,则不共享可能实际上对性能有益:如果每个任务在不同的处理器上运行,则同步共享内存非常昂贵.
*简化. CLONE_THREAD导致信号传递被共享(需要CLONE_SIGHAND,共享信号处理程序表).
**简化.存在两个SYS_fork和SYS_clone系统调用,但在内核中,sys_fork并且sys_clone它们都是围绕同一do_fork函数的非常薄的包装器,它本身就是一个薄的包装器copy_process.是的,术语process,thread以及task相当互换使用Linux内核...
Mar*_*rkR 59
Linux(实际上是Unix)为您提供了第三种选择.
创建一个独立的可执行文件,处理应用程序的某些部分(或所有部分),并为每个进程单独调用它,例如程序运行自身的副本以将任务委派给.
创建一个独立的可执行文件,它以单个线程启动并创建其他线程来执行某些任务
仅在Linux/Unix下可用,这有点不同.分叉进程实际上是它自己的进程,它有自己的地址空间 - 孩子可以(通常)不会影响其父进程或兄弟地址空间(与线程不同) - 所以你可以增加健壮性.
但是,内存页面不会被复制,它们是写时复制的,因此通常使用的内存比您想象的要少.
考虑一个Web服务器程序,它包含两个步骤:
如果您使用了线程,则步骤1将完成一次,而步骤2将在多个线程中完成.如果使用"传统"进程,则需要为每个进程重复步骤1和2,并且存储配置和运行时数据的内存重复.如果您使用了fork(),那么您可以执行第1步,然后执行fork(),将运行时数据和配置保留在内存中,不受影响,不进行复制.
所以真的有三种选择.
Ada*_*eld 51
这取决于很多因素.进程比线程更重,并且具有更高的启动和关闭成本.进程间通信(IPC)也比线程通信更难,更慢.
相反,进程比线程更安全,更安全,因为每个进程都在自己的虚拟地址空间中运行.如果一个进程崩溃或缓冲区溢出,它根本不会影响任何其他进程,而如果一个线程崩溃,它将关闭进程中的所有其他线程,如果一个线程有缓冲区溢出,它会打开所有线程中的安全漏洞.
因此,如果您的应用程序的模块可以在几乎没有通信的情况下独立运行,那么如果您能负担起启动和关闭成本,则应该使用流程.IPC的性能影响将是最小的,您将对错误和安全漏洞稍微安全一些.如果您需要每一点性能,您可以获得或拥有大量共享数据(例如复杂的数据结构),请使用线程.
曾几何时有Unix,在这个老的Unix中有很多进程的开销,所以一些聪明的人做的是创建线程,它将与父进程共享相同的地址空间,他们只需要减少上下文切换,这将使上下文切换更有效.
在当代Linux(2.6.x)中,进程的上下文切换与线程之间的性能差别不大(只有MMU的东西是线程的附加内容).共享地址空间存在问题,这意味着线程中的错误指针可能破坏父进程的内存或同一地址空间内的另一个线程.
进程受MMU保护,因此错误的指针只会导致信号11而不会损坏.
我一般会使用进程(在Linux中没有太多的上下文切换开销,但由于MMU导致的内存保护),但是如果我需要一个实时的调度程序类,那就是pthreads,这是一个不同的茶.
为什么你认为线程在Linux上有如此大的性能提升?你有这方面的数据,还是只是一个神话?
如果您想尽可能创建一个纯进程,您可以使用clone()并设置所有克隆标志。(或者省去打字的麻烦,直接打电话fork())
如果您想尽可能创建一个纯线程,您可以使用clone()并清除所有克隆标志(或者节省自己的打字工作和调用pthread_create())
有 28 个标志指示资源共享的级别。这意味着您可以创建超过 2.68 亿种任务,具体取决于您想要共享的内容。
这就是我们所说的 Linux 不区分进程和线程,而是将程序内的任何控制流视为任务的意思。不区分两者的理由是,没有唯一地定义超过 2.68 亿种口味!
因此,做出使用进程还是线程的“完美决定”实际上就是决定要克隆 28 个资源中的哪一个。
我认为每个人都在回答你的问题时做得很好。我只是在 Linux 中添加更多关于线程与进程的信息,以澄清和总结内核上下文中的一些先前响应。所以,我的回答是关于 Linux 中内核特定的代码。根据 Linux Kernel 文档,除了线程使用共享虚拟地址空间与进程不同之外,线程与进程之间没有明显区别。另请注意,Linux 内核使用术语“任务”来泛指进程和线程。
“没有实现进程或线程的内部结构,而是有一个 struct task_struct 描述了一个称为任务的抽象调度单元”
此外,根据 Linus Torvalds 的说法,您根本不应该考虑进程与线程,因为它的局限性太大,唯一的区别是 COE 或执行上下文在“将地址空间与父级分离”或共享地址空间方面。事实上,他在这里使用了一个 Web 服务器示例来说明他的观点(强烈推荐阅读)。
完全归功于linux 内核文档
| 归档时间: |
|
| 查看次数: |
109569 次 |
| 最近记录: |