Data safety and GIL removal提到如果你没有使用巨型翻译锁,就会增加竞争条件的风险。博客文章给出了以下示例:
# As noted in the blog post, this'll work correctly in MRI Ruby (1.8 or 1.9)
# but may or may not work correctly in Rubinius 2.0 or JRuby
@array, threads = [], []
4.times do
threads << Thread.new { (1..100_000).each {|n| @array << n} }
end
threads.each{|t| t.join }
puts @array.size
我为使代码线程安全而采取的一种方法是进行函数式编程,而不是在线程中修改没有在线程中创建的对象/变量的代码:
threads = 4.times.map do
Thread.new do
sub_array = []
# Modifying sub_array is fine, because it was created by this thread
(1..100_000).each {|n| sub_array << n}
sub_array
end
end
puts threads.map(&:value).flatten(1).size
# Or (and don't forget nil!)
# array = threads.map(&:value).flatten(1) ; nil
# puts array.size
是否可以指定不允许线程修改不属于它的对象/变量,如果出现则引发警告或异常?
假设线程代码没有像调用ObjectSpace.each_object
那样做任何惊人的病态。
答案 0 :(得分:0)
我不知道如何限制Ruby以任何身份访问任何容量的东西,而不是长期以来传统的独立新流程。大多数语言都是这样的,只有很少的例外,正如你所指出的那样,严格的函数式语言就在这个集合中。
这里最负责任的方法是使用Mutex锁定,或者通过保持数据隔离和独立来创建线程安全的类。这需要仔细设计,但如果做得好,您的线程应用程序几乎就像标准应用程序一样简单。