为什么分叉会减缓我的应用程序

3
我的应用程序使用fork系统调用每隔几百毫秒进行一次检查点。但是,当使用检查点(分叉)时,我注意到我的应用程序明显变慢。我测试了fork调用所需的时间,结果为1至2毫秒。那么为什么fork会使我的应用程序变得如此缓慢呢?请注意,我只保留一个检查点(分叉进程),并在获取新检查点时杀死先前的检查点。此外,我的计算机具有巨大的内存。
请注意,我的分叉进程创建后只是休眠。只有在需要回滚时才被唤醒。因此,它不应该由操作系统调度。我想到的一件事是,由于fork是一种写时复制机制,每当我的应用程序修改页面时就会发生页面错误。但这是否会显著减慢应用程序的速度?没有检查点(分叉),我的应用程序大约在3.1秒内完成,而使用检查点后,需要大约3.7秒。您有什么想法,是什么导致了我的应用程序变慢?

3
如果可能的话,你应该使用轻量级且资源消耗较小的线程。相比之下,分叉更加繁重,需要操作系统创建一个全新的进程。请注意,在翻译时不要改变原意。 - linuxuser27
请查看此链接:https://dev59.com/WG865IYBdhLWcg3wM7u0 - linuxuser27
在fork()之后,您在子进程或父进程中修改的每个页面都会导致页面错误,这意味着上下文切换和复制页面。因此,它将直接取决于您的应用程序使用了多少内存以及在fork之后修改了多少内存。 - nos
2
@linuxuser27:如果没有大量的额外工作,线程对于检查点机制是无用的,这正是因为它们 拷贝写进程地址空间(这是使它们比 fork 更轻量级的东西)。 - zwol
@Zack - 我明白了。感谢提供这些信息。那么,我猜MetallicPriest遇到的性能问题只能接受,或者还有其他机制吗? - linuxuser27
显示剩余2条评论
3个回答

8
您猜测的是正确的,您可能已经注意到了写时复制机制的成本。实际上,这相当昂贵——这就是为什么 vfork 仍然存在的原因。(主要成本不是额外的页面错误本身,而是在每个被触及的页面进行 memcpy 和相关的缓存和 TLB 刷新。)它不会显示为 fork 的成本,因为页面错误不会在系统调用内发生。
您可以通过查看 getrusage 报告的时间来确认假设——如果正确,额外的时间几乎都是“系统”时间(在内核内部消耗的 CPU 时间)。oprofileperf 可以让您更具体地确定问题……但是,这些工具非常难以使用。
不幸的是,写时复制也是您的检查点机制能够正常工作的原因。您能否在更长的间隔时间内进行检查点?这是我能想到的唯一快速修复方法。

3
我建议使用 oprofile 来查找。
相信 oprofile 可以对整个系统进行剖析,而不仅仅是单个进程。
你可以与其他检查点包比较,例如 BLCR

1
我认为你不应该推荐那些一直很难让它们做出有用反馈的性能分析工具,而不提前警告人们。不幸的是,这描述了所有Linux内核性能分析工具。 - zwol

2

分叉本质上非常昂贵,因为您正在将现有进程的副本创建为全新的进程。如果速度对您很重要,则应使用线程。

此外,您说分叉的进程会休眠,直到需要“回滚”。我不确定您所说的“回滚”是什么,但只要它是可以放在一个函数中的东西,您就应该将其放在一个函数中,然后创建一个仅运行该函数并在检测到需要回滚时退出的线程。额外的好处是,如果您使用该方法,只有在需要时才创建线程。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接