Giới thiệu về gem Parallel
Parallel là một gem hỗ trợ xử lý song song của ruby. Hiện nay Ruby có 2 thư viện cơ bản Thread và Process. Tuy nhiên có rất nhiều vấn đề khi sử dụng 2 thư viện này cần phải giải quyết . Parallel là một vài thư viện có cách sử dụng khá đơn giản đặc biệt với các tác vụ như đọc và ghi dữ liệu. Sơ ...
Parallel là một gem hỗ trợ xử lý song song của ruby. Hiện nay Ruby có 2 thư viện cơ bản Thread và Process. Tuy nhiên có rất nhiều vấn đề khi sử dụng 2 thư viện này cần phải giải quyết . Parallel là một vài thư viện có cách sử dụng khá đơn giản đặc biệt với các tác vụ như đọc và ghi dữ liệu.
Sơ lược về xử lý song song
- So với lập trình tuần tự, lập trình song song có thể hiểu một cách đơn giản là: lập trình song song chia nhỏ vấn đề đó ra và đưa vào xử lý thành nhiều phần
- Lập trình song song gồm có Multi Threading (đa luồng) và Multiple Processes(đa xử tiến trình)
- Multi Threading: có thể xem như là một chương trình con trong chương trình chính, giao tiếp với nhau thông qua biến toàn cục và theo kiến trúc chia sẻ bộ nhớ. Nếu như chỉ có 1 CPU thì ta vẫn có thể thực hiện kỹ thuật này nhưng không thể xử lý đa nhân được. Tuy nhiên xử lý đa luồng vẫn mang nhiều nét của lập trình tuần tự.
- Multiple Processes: Thường là xử lý trên một tập dữ liệu và đặc tính của nó là xử lý song song các dữ liệu trên mỗi CPU. Nhiều công việc cùng làm chung trên một dữ liệu, mỗi công việc có 1 phân vùng dữ liệu để làm việc riêng.
- Trong rails, xử lý MultiThreading có thể kế đến Sidekiq, Puma, Thin, và Multiple Processes: Unicorn
- Đối với dữ liệu nhỏ, xử lý song song không mang lại hiệu quả cao bằng xử lý tuần tự, tuy nhiên với những dữ liệu lớn, xử lý song song sẽ nhanh hơn rất nhiều.
Cơ bản về gem Parallel
- Cài đặt: gem install parallel
- Parallel có thể xử lý đa luồng và đa tiến trình
Một số func cơ bản cho Multi Theard và Multiple Processes
# 2 CPUs -> work in 2 processes (a,b + c) results = Parallel.map(['a','b','c']) do |one_letter| expensive_calculation(one_letter) end
# 3 Processes -> finished after 1 run results = Parallel.map(['a','b','c'], in_processes: 3) { |one_letter| ... } # 3 Threads -> finished after 1 run results = Parallel.map(['a','b','c'], in_threads: 3) { |one_letter| ... }
Tương tự có thể sử dụng với each
Parallel.each(['a','b','c']) { |one_letter| ... }
ActiveRecord
Các bạn có thể áp dụng parallel cho ActiveRecord
# reproducibly fixes things (spec/cases/map_with_ar.rb) Parallel.each(User.all, in_processes: 8) do |user| user.update_attribute(:some_attribute, some_value) end User.connection.reconnect! # maybe helps: explicitly use connection pool Parallel.each(User.all, in_threads: 8) do |user| ActiveRecord::Base.connection_pool.with_connection do user.update_attribute(:some_attribute, some_value) end end
# maybe helps: reconnect once inside every fork Parallel.each(User.all, in_processes: 8) do |user| @reconnected ||= User.connection.reconnect! || true user.update_attribute(:some_attribute, some_value) end
Break
Parallel.map(User.all) do |user| raise Parallel::Break # -> stops after all current items are finished end
Kill
Chỉ nên sử dụng cách này nếu sub-process an toàn để kill process ở bất kỳ thời điểm nào
Parallel.map([1,2,3]) do |x| raise Parallel::Kill if x == 1# -> stop all sub-processes, killing them instantly sleep 100 end
Worker number
Sử dụng Parallel.worker_number để tìm ra vị trí của worker mà tác vụ đang được thực thi.
Parallel.each(1..5, :in_processes => 2) do |i| puts "Item: #{i}, Worker: #{Parallel.worker_number}" end # Item: 1, Worker: 1 # Item: 2, Worker: 0 # Item: 3, Worker: 1 # Item: 4, Worker: 0 # Item: 5, Worker: 1
Trên đây là giới thiệu sơ bộ về gem parallel. Các bạn có thể tham khảo thêm tại: https://github.com/grosser/parallel