Nếu tôi làmTrở dữ liệu từ các quá trình chia hai
Process.fork do
x
end
làm thế nào tôi có thể biết những gì x trả lại (ví dụ đúng/fase/string)?
(Viết vào một tập tin/cơ sở dữ liệu không phải là một lựa chọn ...)
Nếu tôi làmTrở dữ liệu từ các quá trình chia hai
Process.fork do
x
end
làm thế nào tôi có thể biết những gì x trả lại (ví dụ đúng/fase/string)?
(Viết vào một tập tin/cơ sở dữ liệu không phải là một lựa chọn ...)
Tôi đã bọc tất cả các giải pháp mà tôi tìm thấy trên đường đi (một số vấn đề khác như người dùng thoát + bộ đệm đường ống) vào ruby parallel gem. Bây giờ nó là dễ dàng như:
results = Parallel.map([1,2,3],:in_processes=>4) do |i|
execute_something(i)
end
hoặc
results = Parallel.map([1,2,3],:in_threads=>4) do |i|
execute_something(i)
end
Theo tài liệu:
Nếu một khối được chỉ định, khối đó được chạy trong các tiến trình con, và subprocess kết thúc với một trạng thái bằng không.
Vì vậy, nếu bạn gọi nó với một khối, nó sẽ trả về 0. Ngược lại, nó có chức năng cơ bản giống như các cuộc gọi fork()
hệ thống trên Unix (phụ huynh nhận được PID của tiến trình mới, đứa trẻ nhận nil
).
Làm thế nào có thể trợ giúp này bằng nhận được những gì 'x' trở lại? – grosser
Quá trình con chạy trong một quá trình riêng biệt (rõ ràng), do đó, để có được giá trị của bất kỳ "x" nào, bạn có thể sẽ phải giao tiếp thông qua ổ cắm, đường ống, hoặc một cái gì đó tương tự. Tôi nghi ngờ bạn có thể, ví dụ: đặt các biến bên trong khối được phản ánh bên ngoài khối, vì quá trình con có bộ nhớ riêng biệt, v.v. – mipadi
Giao tiếp ngã ba giữa hai quy trình Unix chủ yếu là mã trả về và không có gì khác. Tuy nhiên, bạn có thể mở một trình đệ trình giữa hai tiến trình và truyền dữ liệu giữa các tiến trình trên trình đệ trình này: đây là cách thức đường ống Unix bình thường.
Nếu bạn chuyển các giá trị Marshal.dump() và Marshal.load(), bạn có thể dễ dàng truyền các đối tượng Ruby giữa các quy trình Ruby đó.
Bạn có thể sử dụng bộ nhớ dùng chung để thực hiện việc này nếu trẻ chỉ cần là một đoạn nhỏ mã ruby. Một cái gì đó như sau sẽ làm việc:
str = 'from parent'
Thread.new do
str = 'from child'
end
sleep(1)
puts str # outputs "from child"
Concurrency có thể được khá khó khăn, tuy nhiên, và truy cập vào bộ nhớ chia sẻ theo cách này là một phần quan trọng trong những lý do - bất cứ lúc nào bạn đã có một biến và quá trình khác có thể thay đổi nó từ dưới bạn, bạn nên rất cảnh giác. Ngoài ra, bạn có thể sử dụng một đường ống, mà là cồng kềnh hơn nhưng có lẽ an toàn hơn cho bất kỳ mã nào nhưng nhỏ nhất, và cũng có thể được sử dụng để chạy bất kỳ lệnh tùy ý nào. Dưới đây là một ví dụ, thẳng ra khỏi rdoc cho IO.popen:
f = IO.popen("uname")
p f.readlines # outputs "Darwin", at least on my box :-)
Chúng tôi thực sự chỉ phải xử lý vấn đề này trong Rails isolation testing. Tôi đã đăng về nó một số on my blog.
Về cơ bản, những gì bạn muốn làm là mở một đường ống trong phụ huynh và trẻ em và để trẻ ghi vào đường ống. Đây là một cách đơn giản để chạy các nội dung của một khối trong một quá trình con và lấy lại kết quả:
def do_in_child
read, write = IO.pipe
pid = fork do
read.close
result = yield
Marshal.dump(result, write)
exit!(0) # skips exit handlers.
end
write.close
result = read.read
Process.wait(pid)
raise "child failed" if result.empty?
Marshal.load(result)
end
Sau đó, bạn có thể chạy:
do_in_child do
require "some_polluting_library"
SomePollutingLibrary.some_operation
end
Lưu ý rằng nếu bạn làm một yêu cầu ở trẻ em , bạn sẽ không có quyền truy cập vào thư viện đó trong phụ huynh, vì vậy bạn không thể trả về một đối tượng thuộc loại đó bằng cách sử dụng phương thức này. Tuy nhiên, bạn có thể trả về bất kỳ loại nào có sẵn trong cả hai. Cũng cần lưu ý rằng rất nhiều chi tiết ở đây (read.close
, Process.wait2(pid)
) chủ yếu là chi tiết về nhà vệ sinh, vì vậy nếu bạn sử dụng rất nhiều, bạn nên chuyển nó vào thư viện tiện ích mà bạn có thể sử dụng lại.
Cuối cùng, lưu ý rằng điều này sẽ không hoạt động trên Windows hoặc JRuby, vì chúng không hỗ trợ forking.
Cảm ơn tất cả các câu trả lời, tôi đã giải pháp của tôi lên và chạy, vẫn cần phải xem làm thế nào để xử lý môi trường không dành forking, nhưng bây giờ nó hoạt động :)
read, write = IO.pipe
Process.fork do
write.puts "test"
end
Process.fork do
write.puts 'test 2'
end
Process.wait
Process.wait
write.close
puts read.read
read.close
bạn có thể nhìn thấy nó trong hành động @parallel_specs Rails plugin
Bạn đã thấy liên kết kiểm tra cách ly mà tôi đã cung cấp trong câu trả lời chưa? Nó xử lý cả hai môi trường forking và không forking, và có thể đã làm tất cả mọi thứ bạn cần. –
Đúng, cũng đọc bài viết của bạn về nó, bị bệnh thêm này sớm! – grosser
Vâng, bạn có thể tạo một tiến trình con để thực hiện một khối bên trong.
Tôi khuyên bạn nên the aw
gem:
Aw.fork! { 6 * 7 } # => 42
Tất nhiên, nó ngăn chặn các tác dụng phụ:
arr = ['foo']
Aw.fork! { arr << 'FUU' } # => ["foo", "FUU"]
arr # => ["foo"]
Bạn có thể vượt qua các đối tượng, hoặc thậm chí là các lớp, làm tham số ở đây không? Tôi thực sự có thể sử dụng một cách để chia rẽ một quá trình và truyền toàn bộ môi trường cho nó. – Automatico