【问题标题】:Is it possible to ensure that threaded code doesn't have side effects in Ruby?是否可以确保线程代码在 Ruby 中没有副作用?
【发布时间】:2011-10-24 22:53:03
【问题描述】:

Data safety and GIL removal 提到,如果您没有安装 Giant Interpreter Lock,则会增加竞争条件的风险。该博客文章给出了以下示例:

# 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

【问题讨论】:

  • “GIL”的意思是“全局解释器锁”,而不是“巨型解释器锁”,虽然我觉得你的解释更有趣。
  • @tadman:我不能为这个 cromulent 词声称功劳:它目前有 2390 次谷歌点击(相对于“全球解释器锁定”的 117K 谷歌点击)。
  • 实际上,我认为 YARV 将其称为 GVL(Giant VM Lock)。 GIL 就是 CPython 所称的。

标签: ruby multithreading thread-safety


【解决方案1】:

我不知道有什么方法可以限制 Ruby 以任何身份访问事物,除了分叉一个独立的新进程的长期传统。大多数语言都是这样,只有极少数例外,正如您所指出的那样,严格的函数式语言都在其中。

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

【讨论】:

  • “大多数语言都是这样的......” - 是因为它难以实现,还是因为它的“需求”很少?
  • 这是因为它意味着程序员需要在某种程度上受到保护,无论意图如何,都会被视为对开发人员怀有敌意。最好的方法是避免共享对相同数据的引用,这样您就不会在多个线程中使用它。
猜你喜欢
  • 2013-02-08
  • 2015-08-08
  • 2015-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-30
  • 1970-01-01
相关资源
最近更新 更多