【问题标题】:exec without replacing current process, posix_spawn kernel implementationexec 不替换当前进程,posix_spawn 内核实现
【发布时间】:2017-05-01 16:09:20
【问题描述】:

尽管内核将页(和页表)标记为写入时复制以使fork 系统调用高效工作,但页表和相关结构的创建和拆除仍然是一项昂贵的任务。

因此,我想知道为什么 linux 社区从未设法将 posix_spawn 实现为一个真正的内核系统调用,它只是产生一个新进程,从而消除了事先调用 fork 的需要。 相反,posix_spawn 只是 forkexec 的一个糟糕的 glibc 包装器。

对于每秒必须产生数千个新进程的工作负载而言,性能提升将非常显着。启动新进程的延迟也会得到改善。

【问题讨论】:

  • 这不是一个好的 SO 问题。也许尝试一些针对 linux 开发的编程 reddits 或邮件列表?另外,作为记录,由于 Windows 上必须发生的所有事情,CreateProcess 比 Linux 上的 fork+exec 慢。 stackoverflow.com/questions/47845/…
  • 我认为在内核中实现 posix_spawn 不会加快速度。这是内核需要做的大部分时间。不是系统调用开销。
  • 如果您想在不分叉新进程和替换进程映像的情况下加载代码,则 dlopen 库或与位置无关的可执行文件。这很快,并且可以让您获得生成新进程的大部分功能,无需一些安全隔离,以及可能的基于 setuid 的权限提升。
  • 你看过vfork吗?
  • 是的,我知道 vfork,我认为解决这个性能问题是一个糟糕的解决方案。就像,嘿,让我们提供一个损坏的 fork 版本,而不是一开始就提供避免 fork 的选项

标签: linux linux-kernel posix system-calls


【解决方案1】:

使用写时复制的分叉非常昂贵。为了说明这一点,您可能需要阅读implementation of classic vfork semantics in NetBSD。该邮件为现实世界的用例(构建软件)提供了一些硬数字。对于非常大的程序,COW 也是一个容易衡量的惩罚。我的一个朋友为他的 Java 应用程序编写了自己的 spawn 守护进程,因为从 8GB+ JVM 中 forking+exec 耗时太长。

现代世界中 vfork 的主要问题是它可能与多线程交互很糟糕。 IE。考虑到 post-vfork 代码必须引用一个尚未被动态链接器解析的函数。动态链接器现在必须锁定自身。例如,这可能会导致原始程序出现死锁。

【讨论】:

  • 这正是我想指出的,大家都认为copy on write效率很高,fork的成本根本不重要,但它仍然涉及更改很多页表条目和然后处理牛次要页面错误,这不是免费的
  • 如您所见,此站点确实不适合较低级别的内容。被赞成的东西通常是不知情的,并且经常重复流行的神话/误解。我只能建议您将此类问题用于例如邮件列表。
【解决方案2】:

这基本上就是posix_spawn 的用途。它也是一个更灵活的 API。真正的错误是 Linux exec 手册页仍然没有包含它的交叉引用。

【讨论】:

  • 实际上我不确定 posix_spawn 是否真的这样做。 stackoverflow.com/questions/2731531/… 解释说它在内部做了某种 vfork。关于手册页:我什至没有在我的本地机器上找到 posix_spawn 的手册页,尽管预装了 fork 和 exec 的综合手册页
  • 听起来posix_spawn 的 Linux 实现是一个 libc 级别的实现,因此您不会像在 BSD 系统上那样减少系统调用的数量,但性能差异无论如何,当fork 使用写时复制实现时,它的影响可以忽略不计。
  • 我不同意这一点,写入时复制仍然涉及迭代大量映射条目和使缓存无效。除此之外:复制流程的整个开销是无用的
  • Posix:此外,尽管它们可能是许多 fork()/exec 对的有效替代品,但它们的目标是为使用 fork() 有困难的系统提供有用的进程创建原语,而不是提供fork()/ exec 的替代品。这种对 posix_spawn() 和 posix_spawnp() 角色的看法影响了它们的 API 设计。它不尝试提供 fork()/exec 的全部功能,其中允许在创建子进程和执行新进程映像之间进行任何用户指定的任意操作
  • 如果没有 fork,我们就不必丢弃想要生成新进程的 current 进程的缓存 tlb 条目。您不能期望清除页表条目的可写位并仍然保持缓存的翻译条目处于活动状态。除此之外,迭代大型进程的 vm 映射结构会导致在执行 fork 期间出现大量缓存未命中。最后,fork 完成后会导致父进程出现一些小故障(例如堆栈页、数据页、堆页),这会减慢父进程的继续执行速度
猜你喜欢
  • 2021-12-30
  • 1970-01-01
  • 1970-01-01
  • 2011-10-08
  • 1970-01-01
  • 2017-04-14
  • 2011-08-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多