【问题标题】:How to fire and forget a subprocess?如何触发并忘记子进程?
【发布时间】:2010-10-22 19:39:30
【问题描述】:

我有一个长时间运行的进程,我需要它来启动另一个进程(它也会运行一段时间)。我只需要启动它,然后完全忘记它。

我设法通过从 Programming Ruby 书中获取一些代码来完成我需要的工作,但我想找到最佳/正确的方法,并了解正在发生的事情。这是我最初得到的:

exec("whatever --take-very-long") if fork.nil?
Process.detach($$)


那么,是这样吗,还是应该怎么做呢?

在检查了下面的答案后,我最终得到了这段代码,这似乎更有意义:

(pid = fork) ? Process.detach(pid) : exec("foo")


我希望能对 fork 的工作原理进行一些解释。 [已经知道了]

分离$$ 对吗?我不知道为什么会这样,我真的很想更好地了解情况。

【问题讨论】:

    标签: ruby unix process fork


    【解决方案1】:

    fork 函数将您的进程一分为二。

    两个 进程然后接收函数的结果。孩子收到零值/nil(因此知道它是孩子),父母收到孩子的 PID。

    因此:

    exec("something") if fork.nil?
    

    将使子进程启动“某事”,而父进程将继续原处。

    注意exec()替换当前进程为“something”,所以子进程永远不会执行任何后续的Ruby代码。

    Process.detach() 的调用看起来可能不正确。我原以为它会包含孩子的 PID,但如果我正确阅读了您的代码,它实际上是在分离父进程。

    【讨论】:

    • 好的,我想我得到了 .nil?查看。在孩子中,它并没有真正返回 0,而是返回 nil。因此,如果您在孩子中,则 exec 将运行。那么,我将如何捕获 fork 的另一个返回,即返回子进程 id 的返回?这样我可以直接使用它而不是依赖 $$.
    • 只需调用 fork 并捕获结果。那么如果你得到 nil,就执行 exec,否则你就在父级中。
    • 这是对“分叉”的清晰简洁的定义。干得好,谢谢。
    【解决方案2】:

    Alnitak 是对的。这是一个更明确的写法,不用$$

    pid = Process.fork
    if pid.nil? then
      # In child
      exec "whatever --take-very-long"
    else
      # In parent
      Process.detach(pid)
    end
    

    detach 的目的只是说,“我不在乎孩子何时终止”以避免zombie processes

    【讨论】:

    • 嗨,我正在玩我新获得的知识,我基本上得到了一个更简洁的版本:(pid = fork)? Process.detach(pid) : exec("foo")
    • @MatthewFlaschen 如果这不包含exec,我不需要在子代码中添加exit 以使僵尸进程不会持续吗?
    • @oldergod,通常程序会在某个时候自然终止。但是,如果子进程中有一个长时间运行的循环,您当然可以在适当的时候调用exit。无论哪种方式,一旦您调用detach,您的父代码就不再需要考虑(Ruby 解释器为您解决僵尸进程问题)。
    【解决方案3】:

    分离$$ 是不对的。从 p。 348 镐(第 2 版):

    $$ Fixnum 正在执行的程序的进程号。 [r/o]

    “Ruby 语言”一章中的“变量和常量”这一部分,对于解码各种 ruby​​ 短 $ 常量非常方便 - 但是在线版(第一个

    因此,您实际上所做的是将程序与其自身分离,而不是与其子程序分离。 正如其他人所说,与孩子分离的正确方法是使用从fork()返回的孩子的pid。

    【讨论】:

    • 有些东西让你的回答变得糟糕。反正我有第三版的镐。所以,$$ 是不对的,事实上。但为什么它仍然有效呢?
    • 如果你在 $$ 上调用 detach,它就不能正常工作。但同样,分离只是为了避免僵尸进程。不必让作业在后台运行。
    【解决方案4】:

    如果您确定要分离子进程,则其他答案很好。但是,如果您不介意,或者更愿意保留子进程(例如,您正在为 Web 应用程序启动子服务器/服务),那么您可以利用以下速记

    fork do
        exec('whatever --option-flag')
    end
    

    提供一个块告诉 fork 在子进程中执行该块(并且只执行该块),同时在父进程中继续执行。

    【讨论】:

      【解决方案5】:

      我发现上面的答案破坏了我的终端并弄乱了输出。这是我找到的解决方案。

         system("nohup ./test.sh &")
      

      以防万一有人遇到同样的问题,我的目标是登录 ssh 服务器,然后让该进程无限期地运行。所以 test.sh 就是这个

      #!/usr/bin/expect -f
      spawn ssh host -l admin -i cloudkey  
      expect "pass"
      send "superpass\r"
      sleep 1000000
      

      【讨论】:

        猜你喜欢
        • 2011-01-09
        • 1970-01-01
        • 1970-01-01
        • 2017-11-30
        • 1970-01-01
        • 2014-12-06
        • 1970-01-01
        • 2021-12-13
        • 1970-01-01
        相关资源
        最近更新 更多