学习Ruby线程-线程完成时触发事件
我是多线程新手,我正在寻找一些帮助,以了解线程完成后执行操作的惯用方法,例如更新进度条。在下面的示例中,我有几个项目和例程列表,用于对每个项目进行“解析”。我计划为每个列表设置一个进度条,以便能够让每个列表的解析例程更新已完成项目的百分比。我看到的唯一“触发器”点是项的sleepy方法(正在线程化的方法)末尾的puts语句。捕获完成的普遍接受的策略是什么,特别是当操作的范围在线程中运行的方法之外时 谢谢学习Ruby线程-线程完成时触发事件,ruby,multithreading,concurrency,threadpool,Ruby,Multithreading,Concurrency,Threadpool,我是多线程新手,我正在寻找一些帮助,以了解线程完成后执行操作的惯用方法,例如更新进度条。在下面的示例中,我有几个项目和例程列表,用于对每个项目进行“解析”。我计划为每个列表设置一个进度条,以便能够让每个列表的解析例程更新已完成项目的百分比。我看到的唯一“触发器”点是项的sleepy方法(正在线程化的方法)末尾的puts语句。捕获完成的普遍接受的策略是什么,特别是当操作的范围在线程中运行的方法之外时 谢谢 # frozen_string_literal: true require 'concur
# 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
#冻结\u字符串\u文字:true
需要“并发”
$stdout.sync=true
班级名单
属性读取器:项目
def初始化(列出\u id,n \u项)
@id=列表\u id
@项目=[]
n|items.times{n|@items问题不是真正的“知道线程何时完成”,而是如何在没有竞争条件的情况下更新共享进度条
解释问题:假设您有一个中心ThreadList#progress\u var
变量,作为每个线程的最后一行,您使用+=
将其递增。这将引入竞争条件,因为两个线程可以同时执行操作(并且可以覆盖彼此的结果)
为了解决这个问题,典型的方法是使用一个基本概念,如果您正在学习多线程,这是一个基本概念
实际实施并没有那么困难:
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\u progress\u bar
方法,而不存在争用条件的风险。谢谢@max pleaner!这让我在理解上有了很大的飞跃。我在列表类的初始化中添加了一个计数器和@semaphore=Mutex.new
呃,我不只是向线程池中添加sleepy,而是增加了synchronize中的计数器。非常简单。现在我只是想弄清楚如何从外部监控线程池,但这是一个完全不同的问题。