为什么在Windows上创建比Linux更昂贵的新流程?

时间:2008-09-06 21:17:43

标签: windows linux performance

我听说在Windows机器上创建新进程比在Linux上更昂贵。这是真的?有人可以解释为什么它更昂贵的技术原因,并为这些原因背后的设计决策提供任何历史原因吗?

10 个答案:

答案 0 :(得分:64)

mweerden:NT从第一天开始就是为多用户设计的,所以这不是一个真正的原因。但是,你是正确的,因为与Unix相比,流程创建在NT上比在Unix上扮演的角色不那么重要,与Unix相比,它支持多线程而不是多处理。

Rob,使用COW时叉子确实比较便宜,但事实上,fork主要是一个exec。并且exec也必须加载所有图像。因此,讨论分支的表现只是事实的一部分。

在讨论创建进程的速度时,区分NT和Windows / Win32可能是一个好主意。至于NT(即内核本身),我认为进程创建(NtCreateProcess)和线程创建(NtCreateThread)并不像普通Unix那样慢得多。可能会有更多的事情发生,但我没有看到这里性能差异的主要原因。

但是,如果你看一下Win32,你会注意到它为进程创建增加了相当多的开销。首先,它要求CSRSS通知涉及LPC的流程创建。它至少需要加载kernel32,并且在将该进程视为完整的Win32进程之前,它必须执行许多额外的簿记工作项。让我们不要忘记解析清单所带来的所有额外开销,检查图像是否需要兼容性垫片,检查软件限制策略是否适用,yada yada。

那就是说,除了原始创建流程,VA空间和初始线程之外,我还看到了所有必须完成的小事情总和的整体放缓。但正如开头所说 - 由于多线程优于多任务处理,唯一受此额外费用影响的软件是移植不良的Unix软件。虽然当Chrome和IE8等软件突然重新发现多处理的好处并开始频繁启动和拆卸流程时,这种情况会发生变化......

答案 1 :(得分:27)

Unix有一个'fork'系统调用,它将当前进程“拆分”为两个,并为您提供第二个进程,该进程与第一个进程相同(以fork调用返回为模)。由于新进程的地址空间已经启动并运行,因此应该比在Windows中调用“CreateProcess”并使其加载exe映像,关联的dll等更便宜。

在fork案例中,OS可以对与两个新进程关联的内存页使用“copy-on-write”语义,以确保每个进程都获得自己随后修改的页面副本。

答案 2 :(得分:23)

添加到JP所说的内容:大部分开销属于Win32启动过程。

Windows NT内核实际上支持COW fork。 SFU(Microsoft的Windows UNIX环境)使用它们。但是,Win32不支持fork。 SFU进程不是Win32进程。 SFU与Win32正交:它们都是在同一内核上构建的环境子系统。

除了CSRSS的进程外LPC调用之外,在XP及更高版本中还有一个对应用程序兼容性引擎的进程外调用,以便在应用程序兼容性数据库中查找该程序。此步骤会导致足够的开销,Microsoft出于性能原因向disable the compatibility engine on WS2003提供组策略选项。

Win32运行时库(kernel32.dll等)也会在启动时执行大量注册表读取和初始化,这些不适用于UNIX,SFU或本机进程。

本机进程(没有环境子系统)创建速度非常快。 SFU在创建流程方面比Win32少得多,因此其创建过程也很快。

2019年更新:添加LXSS:Windows Subsystem for Linux

更换SFU for Windows 10是LXSS环境子系统。它是100%内核模式,不需要Win32继续拥有的任何IPC。这些进程的Syscall直接指向lxss.sys / lxcore.sys,因此fork()或其他创建调用的进程只需要为创建者进行1次系统调用,总计。 [A data area called the instance] keeps track of all LX processes, threads, and runtime state.

LXSS流程基于本机流程,而不是Win32流程。所有Win32特定的东西,如兼容性引擎都没有参与。

答案 3 :(得分:16)

除了Rob Walker的回答: 如今你有像Native POSIX Thread Library这样的东西 - 如果你愿意的话。 但是很长一段时间,在unix世界中“委托”工作的唯一方法是使用fork()(在许多情况下它仍然是首选)。 例如某种套接字服务器

socket_accept()
fork()
if (child)
    handleRequest()
else
    goOnBeingParent()
因此,fork的实现必须很快,并且随着时间的推移已经实现了很多优化。 Microsoft支持CreateThread甚至是光纤,而不是创建新进程和进程间通信的使用。我认为将CreateProcess与fork进行比较并不“公平”,因为它们不可互换。将fork / exec与CreateProcess进行比较可能更合适。

答案 4 :(得分:13)

我认为,这个问题的关键是两个系统的历史用法。 Windows(以及之前的DOS)最初是个人计算机的单用户系统。因此,这些系统通常不必一直创建大量进程; (非常)简单地说,只有当这个孤独的用户请求它时才会创建一个进程(而且我们人类的操作速度非常快,相对而言)。

基于Unix的系统最初是多用户系统和服务器。特别是对于后者,具有分离进程以处理特定作业(例如,处理一个传入连接)的进程(例如,邮件或http守护进程)并不罕见。这样做的一个重要因素是便宜的fork方法(正如Rob Walker(47865所提到的那样),最初对新创建的进程使用相同的内存),这对于新进程非常有用立即获得所需的所有信息。

很明显,至少在历史上,基于Unix的系统需要快速创建流程远远大于Windows系统。我认为情况仍然如此,因为基于Unix的系统仍然是面向流程的,而Windows由于其历史,可能更多地面向线程(线程对于生成响应式应用程序非常有用)。

免责声明:我不是这方面的专家,如果我弄错了,请原谅我。

答案 5 :(得分:9)

简短的回答是“软件层和组件”。

Windows SW体系结构有一些额外的层和组件,这些层和组件在Unix上不存在,或者在Unix内核内部进行了简化和处理。

在Unix上,fork和exec是对内核的直接调用。

在Windows上,内核API不直接使用,win32和其上的某些其他组件,因此创建流程必须经过额外的层,然后新流程必须启动或连接到这些层和组件。

很长一段时间以来,研究人员和企业都试图以模糊的方式分解Unix,通常是将他们的实验基于Mach kernel;一个众所周知的例子是OS X.。然而,每当他们尝试时,它就会变得如此缓慢,最终至少部分地将这些碎片合并到内核中,或者永久地或者用于生产货物。

答案 6 :(得分:8)

呃,似乎有很多“这种方式更好”的理由正在进行中。

我认为人们可以从阅读“Showstopper”中受益;关于Windows NT开发的书。

服务作为DLL在Windows NT上的一个进程中运行的全部原因是它们与单独的进程一样慢。

如果你沮丧和肮脏,你会发现库加载策略是问题所在。

On Unices(通常)共享库(DLL)代码段实际上是共享的。

Windows NT在每个进程中加载​​DLL的副本,因为它在加载后操作库代码段(和可执行代码段)。 (告诉它你的数据在哪里?)

这导致库中的代码段不可重用。

因此,NT进程创建实际上非常昂贵。并且在不利方面,它使得DLL在内存中没有明显的节省,但是存在应用程序间依赖性问题的可能性。

有时候工程学会退后一步说:“现在,如果我们要把它设计得真的很糟糕,那会是什么样子?”

我曾经使用过一种非常有气势的嵌入式系统,有一天看着它并意识到它是一个腔体磁控管,电子器件在微波腔中。之后我们让它变得更加稳定(而不像微波炉)。

答案 7 :(得分:1)

除此之外,还有一个事实是,在Win机器上,很可能一个防病毒软件会在CreateProcess期间启动...这通常是最大的减速。

答案 8 :(得分:1)

值得注意的是,Windows中的安全模型比基于unix的操作系统复杂得多,后者在创建进程时增加了大量开销。多线程的另一个原因是Windows中的多处理优先。

答案 9 :(得分:1)

例如在某些答案中似乎有MS-Windows的合理性

  • “ NT内核和Win32是不一样的。如果您使用NT内核进行编程,那还不错。” —是的,但是除非您正在编写Posix子系统,否则谁在乎。您将要写到win32。
  • “将比较fork与ProcessCreate进行比较是不公平的,因为它们做的是不同的事情,而Windows没有fork” –是的, 所以我会比较喜欢。但是,我还将比较fork,因为它有很多用例,例如进程隔离(例如,Web浏览器的每个选项卡在不同的进程中运行)。

现在让我们看一下事实,性能有何不同?

数据从http://www.bitsnbites.eu/benchmarking-os-primitives/ 汇总。
由于偏见是不可避免的,因此总结时,我偏向于MS-Windows
大多数测试i7 8核心3.2GHz的硬件。除了运行Gnu / Linux的Raspberry-Pi

按照速度的顺序,从最快到最慢(数字是时间,越小越好)。

  • Linux CreateThread 12
  • Mac CreateThread 15
  • Linux Fork 19
  • Windows CreateThread 25
  • Linux CreateProcess(fork + exec)45
  • Mac Fork 105
  • Mac CreateProcess(fork + exec)453
  • Raspberry-Pi CreateProcess(fork + exec)501
  • Windows CreateProcess 787
  • 带有病毒扫描程序2850的Windows CreateProcess
  • Windows Fork(使用CreateProcess + fixup模拟)大于2850

注意: 在Linux fork上比MS-Windows首选方法CreateThread更快。

现在还有其他数字

  • 创建文件。
    • Linux 13
    • Mac 113
    • Windows 225
    • Raspberry-Pi(带有慢速SD卡)241
    • 带有防御程序和病毒扫描程序等的Windows 12950
  • 分配内存
    • Linux 79
    • Windows 93
    • Mac 152