2009-07-02 34 views

Trả lời

9

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 
+2

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

0

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).

+0

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

+0

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

0

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 đó.

0

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 :-) 
30

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.

11

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

+0

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. –

+0

Đúng, cũng đọc bài viết của bạn về nó, bị bệnh thêm này sớm! – grosser

1

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"] 
Các vấn đề liên quan