Khóa học ruby

Multithreading trong Ruby

0 phút đọc

Multithreading là một kỹ thuật lập trình cho phép một chương trình thực thi nhiều luồng (threads) đồng thời. Điều này có thể cải thiện hiệu suất của chương trình bằng cách tận dụng tối đa tài nguyên của hệ thống. Trong Ruby, việc sử dụng multithreading có thể giúp bạn viết các ứng dụng hiệu quả hơn, đặc biệt là khi xử lý các tác vụ I/O hoặc các tác vụ có thể chạy song song. Bài viết này sẽ đi sâu vào các khía cạnh của multithreading trong Ruby, bao gồm cách tạo threads, vòng đời của threads, xử lý exceptions trong threads, biến thread, ưu tiên thread, loại trừ thread, xử lý deadlock, trạng thái thread, các phương thức của lớp Thread và các phương thức của đối tượng Thread.

Tạo Threads trong Ruby (Creating Ruby Threads)

Để tạo một thread trong Ruby, bạn sử dụng lớp Thread và phương thức new. Bạn có thể truyền một khối lệnh cho phương thức new, và khối lệnh này sẽ được thực thi trong thread mới.

thread = Thread.new do
  puts "Hello from the new thread!"
end

thread.join  # Chờ thread kết thúc

Vòng đời của Threads (Thread Lifecycle)

Vòng đời của một thread bao gồm các trạng thái sau:

  1. New: Thread được tạo nhưng chưa bắt đầu thực thi.
  2. Runnable: Thread đang chờ để được thực thi.
  3. Running: Thread đang thực thi.
  4. Blocked: Thread đang chờ một tài nguyên hoặc một điều kiện.
  5. Terminated: Thread đã hoàn thành thực thi hoặc bị kết thúc.

Bạn có thể sử dụng phương thức status để kiểm tra trạng thái của một thread.

thread = Thread.new { sleep(1) }
puts thread.status  # Output: "run" hoặc "sleep"
thread.join
puts thread.status  # Output: "false"

Threads và Exceptions (Threads and Exceptions)

Nếu một exceptions xảy ra trong một thread, thread đó sẽ bị kết thúc trừ khi exceptions được bắt và xử lý. Bạn có thể sử dụng khối begin-rescue để bắt và xử lý exceptions trong thread.

thread = Thread.new do
  begin
    raise "An error occurred"
  rescue => e
    puts "Caught exception: #{e.message}"
  end
end

thread.join

Biến Thread (Thread Variables)

Mỗi thread trong Ruby có thể có các biến riêng của nó, được gọi là biến thread. Bạn có thể sử dụng phương thức Thread#[]Thread#[]= để truy cập và thiết lập các biến thread.

thread = Thread.new do
  Thread.current[:name] = "MyThread"
  puts "Thread name: #{Thread.current[:name]}"
end

thread.join

Ưu tiên Thread (Thread Priorities)

Bạn có thể thiết lập ưu tiên cho một thread bằng cách sử dụng phương thức priority. Giá trị ưu tiên càng cao, thread càng có nhiều cơ hội được thực thi.

thread1 = Thread.new { sleep(1); puts "Thread 1" }
thread2 = Thread.new { sleep(1); puts "Thread 2" }

thread1.priority = 1
thread2.priority = 2

thread1.join
thread2.join

Loại trừ Thread (Thread Exclusion)

Khi nhiều thread truy cập vào cùng một tài nguyên, có thể xảy ra các vấn đề về đồng bộ hóa. Ruby cung cấp các cơ chế để loại trừ thread, chẳng hạn như Mutex (mutual exclusion).

mutex = Mutex.new
counter = 0

threads = 10.times.map do
  Thread.new do
    1000.times do
      mutex.synchronize do
        counter += 1
      end
    end
  end
end

threads.each(&:join)
puts "Counter: #{counter}"  # Output: 10000

Xử lý Deadlock (Handling Deadlock)

Deadlock xảy ra khi hai hoặc nhiều thread chờ đợi lẫn nhau để giải phóng tài nguyên, dẫn đến tình trạng không thread nào có thể tiếp tục. Để tránh deadlock, bạn cần cẩn thận khi sử dụng các cơ chế đồng bộ hóa như Mutex.

mutex1 = Mutex.new
mutex2 = Mutex.new

thread1 = Thread.new do
  mutex1.synchronize do
    sleep(1)
    mutex2.synchronize do
      puts "Thread 1"
    end
  end
end

thread2 = Thread.new do
  mutex2.synchronize do
    sleep(1)
    mutex1.synchronize do
      puts "Thread 2"
    end
  end
end

[thread1, thread2].each(&:join)

Trạng thái Thread (Thread States)

Bạn có thể kiểm tra trạng thái của một thread bằng cách sử dụng các phương thức như alive?, stop?, và status.

thread = Thread.new { sleep(1) }
puts thread.alive?  # Output: true
puts thread.stop?   # Output: false
puts thread.status  # Output: "sleep"
thread.join
puts thread.alive?  # Output: false
puts thread.status  # Output: false

Các phương thức của lớp Thread (Thread Class Methods)

Lớp Thread cung cấp nhiều phương thức hữu ích để làm việc với threads, bao gồm:

  • Thread.new: Tạo một thread mới.
  • Thread.start: Tương tự như Thread.new.
  • Thread.list: Trả về một mảng chứa tất cả các threads.
  • Thread.main: Trả về thread chính.
  • Thread.current: Trả về thread hiện tại.
  • Thread.kill: Kết thúc một thread.
  • Thread.pass: Nhường quyền thực thi cho thread khác.
thread = Thread.new { sleep(1) }
puts Thread.list.inspect  # Output: [#<Thread:0x00007f9c8b0b8b88 run>, #<Thread:0x00007f9c8b0b8b88 sleep>]
puts Thread.main.inspect  # Output: #<Thread:0x00007f9c8b0b8b88 run>
puts Thread.current.inspect  # Output: #<Thread:0x00007f9c8b0b8b88 run>
Thread.kill(thread)

Các phương thức của đối tượng Thread (Thread Instance Methods)

Các đối tượng Thread cung cấp nhiều phương thức hữu ích để làm việc với threads, bao gồm:

  • join: Chờ thread kết thúc.
  • kill: Kết thúc thread.
  • exit: Kết thúc thread.
  • wakeup: Đánh thức thread.
  • priority: Trả về hoặc thiết lập ưu tiên của thread.
  • status: Trả về trạng thái của thread.
  • alive?: Kiểm tra xem thread có đang chạy không.
  • stop?: Kiểm tra xem thread có đang dừng không.
thread = Thread.new { sleep(1) }
thread.wakeup
thread.join
puts thread.status  # Output: false

Các chủ đề bổ sung

Thread Pools

Thread pools là một kỹ thuật quản lý threads, trong đó một nhóm các threads được tạo sẵn và tái sử dụng để thực hiện các tác vụ. Điều này giúp giảm chi phí tạo và hủy threads.

require 'thread'

class ThreadPool
  def initialize(size)
    @size = size
    @jobs = Queue.new
    @pool = Array.new(@size) do
      Thread.new do
        loop do
          job = @jobs.pop
          job.call
        end
      end
    end
  end

  def schedule(&block)
    @jobs << block
  end

  def shutdown
    @size.times do
      schedule { Thread.exit }
    end
    @pool.each(&:join)
  end
end

pool = ThreadPool.new(5)
10.times do |i|
  pool.schedule { puts "Job #{i} done by #{Thread.current}" }
end
pool.shutdown

Kết luận

Multithreading là một kỹ thuật mạnh mẽ trong Ruby, cho phép bạn viết các ứng dụng hiệu quả hơn bằng cách tận dụng tối đa tài nguyên của hệ thống. Bằng cách sử dụng các kỹ thuật và phương pháp được mô tả trong bài viết này, bạn có thể quản lý và đồng bộ hóa các threads một cách hiệu quả, tránh deadlock và tối ưu hóa hiệu suất của ứng dụng. Hãy tiếp tục khám phá và thực hành với multithreading trong Ruby để trở thành một lập trình viên giỏi hơn.

Avatar
Được viết bởi

TechMely Team

Gợi ý câu hỏi phỏng vấn

entry

Ruby on Rails là gì?

entry

Is there an equivalent of “continue” in Ruby?

entry

Is everything in Ruby an object?

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào