是否有可能确保线程代码在Ruby中没有副作用?

时间:2011-10-24 22:53:04

标签: ruby multithreading thread-safety

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那样做任何惊人的病态。

1 个答案:

答案 0 :(得分:0)

我不知道如何限制Ruby以任何身份访问任何容量的东西,而不是长期以来传统的独立新流程。大多数语言都是这样的,只有很少的例外,正如你所指出的那样,严格的函数式语言就在这个集合中。

这里最负责任的方法是使用Mutex锁定,或者通过保持数据隔离和独立来创建线程安全的类。这需要仔细设计,但如果做得好,您的线程应用程序几乎就像标准应用程序一样简单。