Неблокирующий подпроцесс с целлулоидом

Каков наилучший способ порождения подпроцесса без блокировки актера?

Моя цель - запустить несколько команд, и когда они будут выполнены, получить выходные данные и код выхода. Я попробовал это, но, очевидно, блокирует вызов popen:

#!/usr/bin/env ruby

require 'celluloid/current'
require 'celluloid/io'

class MyProcessLauncher
    include Celluloid::IO

    def run
        every(1) { puts "tick" }

        every(5) {
            puts "Starting subprocess"
            ::IO.popen("sleep 10 && echo 'subprocess done'", :err=>[:child, :out]) { |io|
                puts io.read
            }
            puts $?.exitstatus
        }
    end
end

MyProcessLauncher.new.run
sleep

Выход:

tick
tick
tick
tick
Starting subprocess
subprocess done
0
tick
Starting subprocess

но я ожидаю пять "галочек" между каждым "Стартовым подпроцессом"...

Спасибо!

1 ответ

Решение

Вам нужно defer или использовать future если вы хотите вернуть значение.

defer (легко, если вам не нужно возвращаться)

В вашем every(5) блок, чтобы использовать deferзаверните popen вызов (включая отображение состояния выхода) с defer {}

future (немного сложнее)

Есть несколько способов реализовать этот подход. Мое предложение было бы перенести содержимое every(5) к своему собственному методу, и инициализировать массив @futures или подобное при запуске MyProcessLauncher... тогда используйте это внутри every(5) вызов:

@futures = future.new_method

Кроме того, добавьте новый цикл для обработки вашего будущего. После every(5) добавить новый обработчик (либо другой every петля или async вызовите процессорный метод, который является рекурсивным) для обработки ваших значений, по сути, делая это:

value = @futures.pop.value if @futures.any?

Я бы задал дополнительный вопрос о фьючерсах, если у вас есть проблемы и вы не можете найти примеры того, как обрабатывать фьючерсы. В противном случае, у вас есть два способа справиться popen звонки без блокировки.

Другие вопросы по тегам