2010-10-25 14 views
6

Tôi đã xem xét khả năng xử lý song song/không đồng bộ của Ruby và đọc nhiều bài viết và bài đăng trên blog. Tôi đã xem qua EventMachine, Fibers, Revactor, Reia, v.v. Thật không may, tôi không thể tìm ra giải pháp đơn giản, hiệu quả (và không phải IO-blocking) cho trường hợp sử dụng rất đơn giản này:Xử lý đồng thời/xử lý đồng bộ Ruby (với trường hợp sử dụng đơn giản)

File.open('somelogfile.txt') do |file| 
    while line = file.gets  # (R) Read from IO 
    line = process_line(line) # (P) Process the line 
    write_to_db(line)   # (W) Write the output to some IO (DB or file) 
    end 
end 

là bạn có thể thấy, kịch bản nhỏ của tôi đang thực hiện ba hoạt động đọc (R), quá trình (P) & ghi (W). Giả sử - vì đơn giản - đó mỗi hoạt động có chính xác 1 đơn vị thời gian (ví dụ 10ms), do đó mã hiện tại sẽ làm điều gì đó như thế này (5 dòng):

Time:  123456789(15 units in total) 
Operations: RPWRPWRPWRPWRPW 

Nhưng, tôi muốn nó làm điều gì đó như thế này:

Time:  1234567 (7 units in total) 
Operations: RRRRR 
      PPPPP 
       WWWWW 

Rõ ràng, tôi có thể chạy ba quá trình (đọc, xử lý & nhà văn) và vượt qua đọc các dòng từ người đọc vào hàng đợi xử lý và sau đó vượt qua dòng chế biến thành hàng đợi nhà văn (tất cả điều phối thông qua ví dụ RabbitMQ) . Nhưng, trường hợp sử dụng rất đơn giản, nó không cảm thấy đúng.

Bất kỳ manh mối nào về cách thực hiện điều này (không chuyển từ Ruby sang Erlang, Closure hoặc Scala)?

+1

Các bài viết có nên được gọi theo cùng thứ tự như khi được đọc không? –

+0

Không, đó là toàn bộ vấn đề mà họ có thể hoàn toàn không đồng bộ. – Dim

Trả lời

1

Khám phá đào (http://peach.rubyforge.org/). Thực hiện song song "mỗi" không thể đơn giản hơn. Tuy nhiên, như các tài liệu nói, bạn sẽ cần phải chạy theo JRuby để sử dụng luồng bản địa của JVM.

Xem phản hồi của Jorg Mittag với this SO question để biết nhiều chi tiết về khả năng đa luồng của các trình thông dịch Ruby khác nhau.

+0

Hmm, đào không thực sự là thứ tôi đang tìm kiếm. Tôi không muốn chạy RPW song song, tôi muốn tách nhiệm vụ 3 ra khỏi nhau và chạy chúng một cách không đồng bộ. Phản ứng của Jorg Mittag đưa ra một giới thiệu tuyệt vời. Tôi nhận thức rõ về các tùy chọn được cung cấp, nhưng không ai trong số họ có vẻ có câu trả lời cho vấn đề của tôi. – Dim

3

Nếu bạn cần nó thực sự song song (từ một quy trình đơn lẻ), tôi tin rằng bạn sẽ phải sử dụng JRuby để nhận các chuỗi gốc thực sự và không có GIL.

Bạn có thể sử dụng một cái gì đó như DRb để phân phối quá trình xử lý trên nhiều quy trình/lõi, nhưng đối với trường hợp sử dụng của bạn, điều này hơi nhiều. Thay vào đó, bạn có thể thử có nhiều quy trình giao tiếp bằng cách sử dụng đường ống:

$ cat somelogfile.txt | ruby ./proc-process | ruby ./proc-store 

Trong trường hợp này, mỗi phần là quá trình riêng có thể chạy song song nhưng đang giao tiếp bằng STDIN/STDOUT. Đây có lẽ là cách tiếp cận dễ nhất (và nhanh nhất) cho vấn đề của bạn.

# proc-process 
while line = $stdin.gets do 
    # do cpu intensive stuff here 
    $stdout.puts "data to be stored in DB" 
    $stdout.flush # this is important 
end 

# proc-store 
while line = $stdin.gets do 
    write_to_db(line) 
end 
+1

Tôi nghĩ rằng GIL của Ruby 1.9 cho phép bạn thực hiện các công cụ CPU trong một luồng trong khi một luồng khác làm I/O - nghĩa là, nó chỉ cấm hai luồng làm công cụ CPU. –

+0

Bạn đang nói về sợi?Sự hiểu biết hạn chế của tôi về sợi là thay vì các chủ đề mà mỗi người có một số tiền chia sẻ của CPU thời gian mã của bạn rõ ràng tay xử lý để sợi có thể xử lý các hoạt động IO chặn và ngay lập tức trở lại mã gọi. Điều này làm giảm lượng thời gian bạn chờ đợi, nhưng tôi không nghĩ rằng nó sẽ cho phép bạn mở rộng hơn một CPU cho mỗi quá trình. Tôi nghĩ rằng GIL có nghĩa là chỉ có một luồng thực thi có thể chạy tại bất kỳ thời điểm nào. http://www.igvita.com/2009/05/13/fibers-cooperative-scheduling-in-ruby/ – JEH

+2

Sử dụng đường ống là một giải pháp tốt để tách vấn đề thành 3 quy trình riêng biệt, nhưng nó không phải là không đồng bộ. Đó là thực tế là một "cách giải quyết Ruby", do đó khá khó thực hiện trong phạm vi của một ứng dụng lớn hơn. "Vấn đề" tôi đã nêu ở trên là một ví dụ đơn giản về xử lý định hướng IO. Tôi đang cố gắng hiểu những gì Ruby có khả năng trong lĩnh vực này và những gì nó có thể thiếu. – Dim