使用Kernel#fork进行后台处理,专业人员?利弊?

jsh*_*rpe 7 ruby background ruby-on-rails backgroundrb delayed-job

我想要一些关于是否使用fork {}来"跟踪"来自rails应用程序的进程是一个好主意的想法......

从我收集的叉子{my_method; Process#setsid}确实做了它应该做的事情.

1)使用不同的PID创建另一个进程

2)不会中断调用过程(例如,它继续等待fork完成)

3)执行孩子直到完成

..这很酷,但这是个好主意吗?叉子到底在做什么?它是否在内存中创建了我的整个rails mongrel/passenger实例的重复实例?如果是这样那将是非常糟糕的.或者,它是否以某种方式在不消耗大量内存的情况下进行.

我的最终目标是取消我的后台守护程序/队列系统,支持分叉这些进程(主要是发送电子邮件) - 但如果这不能节省内存,那么它肯定是向错误方向迈出的一步

Dig*_*oss 5

分支确实会复制您的整个过程,并且,也取决于您与应用服务器的连接方式,这确实是一个复制。如在其他讨论中所述,这是通过复制完成的,因此可以容忍。毕竟,Unix是基于fork(2)构建的,因此它必须相当快地对其进行管理。请注意,还将复制任何部分缓冲的I / O,打开的文件以及许多其他内容,以及弹簧加载以将其写出的程序状态,这将是不正确的。

我有几点想法:

  • 您正在使用Action Mailer吗?看来使用AM或类似方法很容易完成电子邮件Process.popen。(Popen会进行派生,但是会紧随其后执行。)
  • 通过执行Process.exec另一个ruby解释器以及您的功能,可以立即摆脱所有状态。如果要传输的状态太多,或者您确实需要使用这些重复的文件描述符,则可以执行类似的操作,IO#popen以便可以发送子流程工作。系统将自动与父级共享包含子流程的Ruby解释器文本的页面。
  • 除了上述内容之外,您可能还需要考虑使用daemonsgem。虽然您的rails进程已经是一个守护程序,但是使用gem可以使保持一个后台任务作为批处理作业服务器运行变得更加容易,并且可以轻松启动,监视,重新启动(如果炸弹了)以及在运行时关闭。 。
  • 如果您确实从fork(2)ed子流程中退出,请使用exit!代替exit
  • 像您一样,已经设置了消息队列和守护程序,听起来对我来说是一个不错的解决方案:-)


wde*_*aum 0

fork 的语义是将进程的整个内存空间复制到新进程中,但许多(大多数?)系统将通过仅复制虚拟内存表并将其标记为写入时复制来实现这一点。这意味着(至少一开始)它不会使用更多的物理内存,仅足以创建新表和其他每个进程的数据结构。

也就是说,我不确定 Ruby、RoR 等与写时复制分叉的交互效果如何。特别是,如果垃圾收集涉及许多内存页面(导致它们被复制),则可能会出现问题。