我想知道使用 fork{} 从 Rails 应用程序“后台”处理是否是个好主意...
从我收集到的 fork{my_method; Process#setsid} 实际上做了它应该做的事情。
1) 创建另一个具有不同 PID 的进程
2) 不中断调用过程(例如它继续 w/o 等待 fork 完成)
3) 执行子进程直到它完成
..这很酷,但这是个好主意吗? fork到底在做什么?它会在内存中创建我的整个 rails mongrel/passenger 实例的重复实例吗?如果是这样那就太糟糕了。或者,它是否以某种方式在不消耗大量内存的情况下完成。
我的最终目标是取消我的后台守护进程/队列系统,转而支持这些进程的 fork (主要是发送电子邮件)——但如果这不能节省内存,那么它肯定是朝着错误的方向迈出了一步
最佳答案
fork 确实会复制您的整个流程,并且根据您连接到应用程序服务器的方式,还会复制一份。正如在其他讨论中指出的那样,这是通过写时复制 完成的,因此这是可以容忍的。毕竟,Unix 是围绕 fork(2) 构建的,因此它必须相当快地管理它。请注意,还会复制任何部分缓冲的 I/O、打开的文件和许多其他内容,以及 Spring 加载以写出它们的程序状态,这是不正确的。
我有几点想法:
- 您在使用 Action Mailer 吗?似乎电子邮件可以通过 AM 或
Process.popen
等方式轻松完成。 (Popen 将进行一次 fork ,但紧随其后的是 exec。) - 通过执行另一个 ruby 解释器的
Process.exec
以及您的功能,立即摆脱所有这些状态。如果要传输的状态太多,或者您确实需要使用那些重复的文件描述符,您可能会执行类似IO#popen
的操作,这样您就可以将子进程的工作发送出去。系统会自动将包含子进程Ruby解释器文本的页面分享给父进程。 - 除了上述之外,您可能还需要考虑使用
daemons
gem。虽然您的 rails 进程已经是一个守护进程,但使用 gem 可以更轻松地保持一个后台任务作为批处理作业服务器运行,并使其易于启动、监视、在它崩溃时重新启动以及在您这样做时关闭。 . - 如果您确实从
fork(2)
ed 子进程中退出,请使用exit!
而不是exit
- 像您一样设置好消息队列和守护进程,这对我来说是个不错的解决方案:-)
关于ruby-on-rails - 使用 Kernel#fork 进行后台进程,专业人士?缺点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1568176/