我是多线程技术的新手,我正在寻找一些帮助,以帮助您理解线程完成后的惯用方式,例如更新进度条。在下面的示例中,我有一些项目和例程的列表,以对每个项目进行一些“解析”。我计划为每个列表提供一个进度条,因此我希望能够使每个列表的解析例程更新已完成项目的百分比。我看到的唯一“触发”点是在项困方法(被线程化的方法)末尾的puts语句处。捕获完成通常被接受的策略是什么,特别是当操作的范围超出线程中运行的方法的范围时?
谢谢!
# frozen_string_literal: true
require 'concurrent'
$stdout.sync = true
class TheList
attr_reader :items
def initialize(list_id, n_items)
@id = list_id
@items = []
n_items.times { |n| @items << Item.new(@id, n) }
end
def parse_list(pool)
@items.each do |item|
pool.post { item.sleepy(rand(3..8)) }
end
end
end
class Item
attr_reader :id
def initialize (list_id, item_id)
@id = item_id
@list_id = list_id
end
def sleepy(seconds)
sleep(seconds)
# This puts statement signifies the end of the method threaded
puts "List ID: #{@list_id} item ID:#{@id} slept for #{seconds} seconds"
end
end
lists = []
5.times do |i|
lists << TheList.new(i, rand(5..10))
end
pool = Concurrent::FixedThreadPool.new(Concurrent.processor_count)
lists.each do |list|
list.parse_list(pool)
end
pool.shutdown
pool.wait_for_termination
最佳答案
问题并不是真正的“知道线程何时完成”,而是如何在没有竞争条件的情况下更新共享进度栏。
解释这个问题:假设您有一个中央ThreadList#progress_var
变量,并且作为每个线程的最后一行,您使用+=
对其进行了递增。因为两个线程可以同时执行该操作(并且可能覆盖彼此的结果),所以这会引入竞争条件。
为了解决这个问题,典型的方法是使用Mutex,这是了解您是否正在学习多线程的基本概念。
实际的实现并不困难:
require 'mutex'
class ThreadList
def initialize
@semaphore = Mutex.new
@progress_bar = 0
end
def increment_progress_bar(amount)
@semaphore.synchronize do
@progress_bar += amount
end
end
end
由于存在@semaphore.synchronize
块,因此您现在可以从线程中安全地调用此increment_progress_bar
方法,而不必担心出现竞争状况。
关于ruby - 学习Ruby线程-线程完成时触发事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65376347/