【问题标题】:Why is the << operation on an array in Ruby not atomic?为什么 Ruby 中数组的 << 操作不是原子的?
【发布时间】:2013-07-19 20:40:28
【问题描述】:

在 Ruby 中,如果 array 被多个线程修改,则此代码不是线程安全的:

array = []
array << :foo # many threads can run this code

为什么&lt;&lt; 操作不是线程安全的?

【问题讨论】:

    标签: ruby multithreading thread-safety atomic


    【解决方案1】:

    实际上使用 MRI(Matz 的 Ruby 实现),GIL(全局解释器锁)可以使任何纯 C 函数原子化。

    由于Array#&lt;&lt; 在 MRI 中被实现为纯 C 代码,因此该操作将是原子的。但请注意,这仅适用于 MRI。在 JRuby 上,情况并非如此。

    为了完全理解发生了什么,我建议你阅读这两篇文章,它们很好地解释了一切:

    Nobody Understands the GIL
    Nobody Understands the GIL - part 2

    【讨论】:

    • 链接失效了
    • @Dennis 感谢您的报告。我用 Wayback Machine 链接替换了它们。现在应该可以工作了。
    【解决方案2】:

    如果您有多个线程访问同一个数组,请使用 Ruby 的内置 Queue 类。它很好地处理了生产者和消费者。

    这是文档中的示例:

    require 'thread'
    
    queue = Queue.new
    
    producer = Thread.new do
      5.times do |i|
        sleep rand(i) # simulate expense
        queue << i
        puts "#{i} produced"
      end
    end
    
    consumer = Thread.new do
      5.times do |i|
        value = queue.pop
        sleep rand(i/2) # simulate expense
        puts "consumed #{value}"
      end
    end
    
    consumer.join
    

    【讨论】:

      【解决方案3】:

      array 是您应用&lt;&lt; 之类的操作时的程序变量。它分三步进行:

      • 首先将变量复制到 CPU 寄存器中。
      • CPU 执行计算。
      • CPU 将结果写回变量内存。

      所以这个高级的单一操作分三步执行。在这些步骤之间,由于线程上下文切换,其他线程可能读取变量的相同(旧)值。这就是为什么它不是原子操作。

      【讨论】:

      • 您可能喜欢阅读:Atomic Operations in Ruby
      • @theTinMan 非常感谢!我的英语很差:(但我仔细注意到你和以前对我的答案进行了编辑,我会在下一个答案中改进。谢谢!
      • 没关系。不需要谢谢。这是我们回馈社区的一部分。
      • 这是 C 或汇编中的数组操作。在 Ruby 中,它还涉及方法查找、参数处理等。
      【解决方案4】:

      因为 Ruby 是一种非常高级的语言,所以在操作系统级别上没有什么是真正原子的。只有非常简单的汇编操作在 OS 级别是原子的(OS 依赖),而每个 Ruby 操作,即使是一个简单的1 + 1 对应于执行的数百或数千条汇编指令,例如方法查找、垃圾收集、对象初始化、范围计算等。

      如果您需要使操作原子化,请使用互斥锁。

      【讨论】:

        【解决方案5】:

        只是模仿@Linuxios 和@TheTinMan:高级语言(HLL)操作通常不是原子的。原子性(通常)在单线程程序中不是问题。在多线程程序中,您(程序员)必须以比单个 HLL 操作更高的粒度对其进行推理,因此具有原子的单个 HLL 操作实际上对您没有太大帮助。另一方面,尽管使 HLL 操作成为原子操作前后只需要几条机器指令——至少在现代硬件上——静态(二进制大小)和动态(执行时间)开销加起来。更糟糕的是,显式原子性几乎禁用了所有优化,因为编译器无法跨原子操作移动指令。没有真正的好处 + 巨大的成本 = 无法启动。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-11-19
          • 2021-07-24
          • 2014-09-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多