我想了解一下是否使用fork {}来“跟踪”一个来自rails应用程序的进程是一个好主意是不是......
从我收集的叉子{my_method; Process#setsid}确实做了它应该做的事情。
1)使用不同的PID
创建另一个进程2)不会中断调用过程(例如,它继续等待fork完成)
3)执行孩子直到完成
..这很酷,但这是个好主意吗?叉子到底在做什么?它是否在内存中创建了我的整个rails mongrel / passenger实例的重复实例?如果是这样那将是非常糟糕的。或者,它是否在不消耗大量内存的情况下以某种方式进行。
我的最终目标是取消我的后台守护程序/队列系统,支持分叉这些进程(主要是发送电子邮件) - 但如果这不会节省内存,那么它肯定是朝错误方向迈出的一步
答案 0 :(得分:4)
fork确实会复制整个过程,并且根据您与应用程序服务器的确切联系方式,也可以复制该过程。正如在其他讨论中所指出的,这是通过 copy-on-write 完成的,因此它是可以容忍的。毕竟,Unix是基于fork(2)构建的,所以它必须相当快地管理它。请注意,任何部分缓冲的I / O,打开的文件以及许多其他内容也会被复制,以及弹出的程序状态将其写出来,这是不正确的。
我有几点想法:
Process.popen
轻松完成。 (Popen会做一个分叉,但紧接着是一个exec。)Process.exec
加上你的功能,立即摆脱所有状态。如果要传输的状态太多或者您确实需要使用这些重复的文件描述符,则可能会执行IO#popen
之类的操作,以便您可以发送子进程工作。系统将自动与父进程共享包含子进程的Ruby解释器文本的页面。daemons
gem。虽然您的rails进程已经是一个守护进程,但使用gem可以更容易地将一个后台任务作为批处理作业服务器运行,并使其易于启动,监视,重启(如果它被炸弹),并在您执行时关闭。 fork(2)
ed子流程,请使用exit!
代替exit
答案 1 :(得分:1)
请注意,它会阻止您在Rails上使用JRuby,因为fork()尚未实现。
答案 2 :(得分:0)
fork的语义是将进程的整个内存空间复制到一个新进程中,但是许多(大多数?)系统只需复制一个虚拟内存表并将其标记为copy-on-write即可。 。这意味着(起初,至少)它不会使用更多的物理内存,只足以制作新表和其他每个进程的数据结构。
那就是说,我不确定Ruby,RoR等与copy-on-write forking的交互程度。特别是如果垃圾收集涉及许多内存页面(导致它们被复制),则可能会出现问题。