Неблокирующий подпроцесс с целлулоидом
Каков наилучший способ порождения подпроцесса без блокировки актера?
Моя цель - запустить несколько команд, и когда они будут выполнены, получить выходные данные и код выхода. Я попробовал это, но, очевидно, блокирует вызов 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
звонки без блокировки.