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


101

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

Answers:


68

mweerden:NT从一开始就为多用户设计的,因此这并不是真正的原因。但是,您对的是,进程创建在NT上的作用不如在Unix上重要,因为与Unix相比,NT与Unix相比,主张多线程而不是多处理。

Rob,确实,使用COW时fork相对便宜,但是事实上,fork后面紧跟着一个执行程序。执行人员也必须加载所有图像。因此,讨论前叉的性能只是事实的一部分。

在讨论进程创建的速度时,最好区分NT和Windows / Win32。就NT(即内核本身)而言,我认为进程创建(NtCreateProcess)和线程创建(NtCreateThread)不会比一般Unix显着慢。可能还有更多事情要做,但是我看不出性能差异的主要原因。

但是,如果您查看Win32,您会注意到它会增加很多创建过程的开销。首先,它要求CSRSS通知有关过程创建的过程,这涉及LPC。它至少需要另外加载kernel32,并且必须执行许多其他的簿记工作项目,然后才能将该进程视为完整的Win32进程。而且,我们不要忘记解析清单所带来的所有额外开销,检查映像是否需要兼容性填充程序,检查软件限制策略是否适用(yada yada)。

就是说,除了进程的原始创建,VA空间和初始线程之外,我还看到所有必须做的小事情的总和总体下降。但是正如一开始所说的那样-由于多线程比多任务更受青睐,因此唯一受到此额外费用严重影响的软件就是移植性差的Unix软件。尽管当Chrome和IE8之类的软件突然重新发现多处理的优势并开始频繁启动和拆卸过程时,这种情况发生了变化。


8
Fork并不总是紧跟exec(),人们只关心fork()。Apache 1.3在Linux上使用fork()(不带exec),在Windows上使用线程,即使在许多情况下,在需要它们并保留在一个池中之前也将它们分叉。
Blaisorblade

5
当然,不要忘记'vfork'命令,该命令是针对您描述的'just call exec'方案设计的。
克里斯·黄·利弗

4
受到这种情况严重影响的另一种软件是任何涉及多个进程协调的shell脚本。例如,Cygwin中的Bash脚本受此困扰。考虑一个在循环中产生大量sed,awk和grep的shell循环。每个命令都生成一个进程,每个管道都生成一个子外壳,并在该子外壳中生成一个新进程。Unix在设计时就考虑到了这种用法,这就是为什么快速创建进程仍然是规范的原因。
Dan Moulding

5
-1。声称软件“移植不当”是因为它在设计不良的操作系统上无法很好地运行,该操作系统充满了兼容性问题,从而减慢了流程创建的速度。
Miles Rout

6
@MilesRout移植的目标是修改软件以使其在新的目标系统上运行,同时牢记该系统的优点和缺点。不管操作系统提供的障碍如何,移植软件执行不佳就是移植软件质量不佳。
Dizzyspiral

28

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

在分叉的情况下,OS可以对与这两个新进程相关联的内存页面使用“写时复制”语义,以确保每个人都获得他们自己随后修改的页面的副本。


22
仅当您真正分叉时,此参数才成立。如果要启动一个新进程,则在Unix上,您仍然必须派生并执行。Windows和Unix都具有复制副本。如果您运行应用程序的第二个副本,Windows肯定会重用已加载的EXE。对不起,我认为您的解释不正确。
乔尔·斯波斯基

1
有关exec()和fork()的更多信息vipinkrsahu.blogspot.com/search/label/system%20programming
webkul,2009年

我在答案中添加了一些性能数据。stackoverflow.com/a/51396188/537980您可以看到它更快。
ctrl-alt-delor

25

JP补充说:该过程的大部分开销属于Win32启动。

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

CSRSSXP和更高版本中,除了对LPC 的进程外调用之外,还存在对应用程序兼容性引擎的进程外调用,以在应用程序兼容性数据库中查找程序。此步骤导致足够的开销,Microsoft 出于性能原因提供了一个组策略选项来禁用WS2003上的兼容性引擎

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

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

2019年更新:添加LXSS:Linux的Windows子系统

LXSS环境子系统是替换Windows 10的SFU。它是100%内核模式,不需要Win32继续拥有的任何IPC。这些进程的系统调用直接定向到lxss.sys / lxcore.sys,因此fork()或其他创建调用的进程对于创建者仅花费1个系统调用,总计。[称为实例的数据区域]跟踪所有LX进程,线程和运行时状态。

LXSS进程基于本机进程,而不是Win32进程。完全没有使用诸如兼容性引擎之类的所有Win32特定功能。


16

除了Rob Walker的答案:如今,如果需要,您还可以使用Native POSIX Thread Library之类的东西。但是很长一段时间以来,在unix世界中“委托”工作的唯一方法是使用fork()(在许多情况下,它仍然是首选)。例如某种套接字服务器

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


2
关于您的最后一点:fork()不能与CreateProcess()交换,但是也可以说Windows应该然后实现fork(),因为这样可以提供更大的灵活性。
Blaisorblade

啊,动词To Bee。
acib708

但是在Linux中,fork + exec比MS-Windows上的CreateThread快。而且Linux可以自己进行分叉,从而更快。但是,您比较一下,MS速度较慢。
ctrl-alt-delor

13

我认为,这件事的关键是两个系统的历史用法。Windows(以前是DOS)最初是个人计算机的单用户系统。因此,这些系统通常不必始终创建很多进程;(非常)简单地说,只有在这个孤独的用户请求时才会创建一个流程(相对而言,我们人类的运行速度并不快)。

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

显然,至少从历史上看,基于Unix的系统具有快速的进程创建的需求远远大于Windows系统。我认为情况仍然如此,因为基于Unix的系统仍然非常面向过程,而Windows由于其历史悠久,可能更多地面向线程(线程对于响应式应用程序很有用)。

免责声明:我绝不是这个问题的专家,如果我理解错了,请原谅我。


9

嗯,似乎有很多“这样更好”的理由。

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

在Windows NT上,服务在一个进程中以DLL的形式运行的全部原因是,它们作为单独的进程太慢了。

如果您摔倒了,就会发现库加载策略是问题所在。

实际上,在Unices上,共享库(DLL)的代码段实际上是共享的。

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

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

因此,NT进程创建实际上非常昂贵。不利的一面是,它使DLL没有明显的内存节省,但有可能导致应用间依赖问题。

有时候回头说“现在,如果我们要设计出真正吸引人的东西,那会是什么样子呢?”

我曾经使用过一种非常有气质的嵌入式系统,有一天看着它,发现它是一个空腔磁控管,而电子器件位于微波空腔中。在那之后,我们使它变得更加稳定(而不像微波炉)。


3
只要DLL加载到其首选的基地址,代码段就可以重用。传统上,您应该确保为将加载到您的进程中的所有DLL设置无冲突的基址,但是不适用于ASLR。
Mike Dimmick

有一些工具可以使所有DLL变基,不是吗?不知道对ASLR有什么作用。
Zan Lynx

3
代码段的共享也适用于启用了ASLR的系统。
约翰尼斯

@MikeDimmick,因此每个制作DLL的人都必须合作,以确保没有冲突,或者在加载之前在系统级别上对它们进行修补?
ctrl-alt-delor

9

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

Windows SW体系结构具有Unix上不存在或在Unix上的内核内部进行简化和处理的几个附加层和组件。

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

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

一段时间以来,研究人员和公司一直试图以一种模糊的相似方式来破坏Unix,通常将他们的实验基于Mach内核。一个著名的例子是OSX。但是,每次尝试时,它都变得如此缓慢,最终最终导致它们至少部分地永久性地或为了生产目的而部分地合并回内核。


层不一定会减慢速度:我用C语言编写了一个设备驱动程序,其中包含许多层。整洁的代码,有素的编程,易于阅读。它比用高度优化的汇编器编写的没有层的版本要快(略)。
ctrl-alt-delor

具有讽刺意味的是,NT是一个巨大的内核(不是微内核)
ctrl-alt-delor

2

似乎在某些答案中有一些MS-Windows的理由,例如

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

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

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

Gnu / Linux,Apple-Mac和Microsoft Windows上各种基本操作的比较(越小越好)

MS-Windows进程创建与Linux的比较

注意:在linux上,fork它比MS-Window的首选方法更快CreateThread

流程创建类型操作的数字(因为很难在图表中看到Linux的值)。

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

  • Linux CreateThread 12
  • Mac CreateThread 15
  • Linux Fork 19
  • Windows CreateThread 25
  • Linux CreateProcess(fork + exec)45
  • 麦克叉105
  • Mac CreateProcess(fork + exec)453
  • Raspberry-Pi CreateProcess(fork + exec)501
  • Windows创建过程787
  • Windows CreateProcess与病毒扫描程序2850
  • Windows Fork(使用CreateProcess + fixup模拟)大于2850

其他测量编号

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

1

所有这些加上事实是,Win机器上很可能在CreateProcess期间启动了防病毒软件……这通常是最大的减速。


1
是的,这是最大的,但不是唯一的显着放缓。
ctrl-alt-delor

1

还值得注意的是,Windows中的安全模型比基于UNIX的OS复杂得多,这在创建过程中增加了很多开销。在Windows中,多线程优先于多处理的另一个原因。


1
我希望更复杂的安全模型更加安全。但事实却相反。
Lie Ryan

4
SELinux也是一个非常复杂的安全模型,它不会增加很大的开销fork()
Spudd86

6
@LieRyan,根据我的经验,在软件设计中,更复杂的方法很少意味着更安全。
Woodrow Douglass
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.