【问题标题】:Does ruby have the Java equivalent of synchronize keyword?ruby 是否有 Java 等效的 synchronize 关键字?
【发布时间】:2011-03-13 14:46:04
【问题描述】:

ruby 是否有 Java 等效的 synchronize 关键字?我正在使用 1.9.1,但我并没有看到一种优雅的方式来做到这一点。

【问题讨论】:

    标签: ruby multithreading synchronize


    【解决方案1】:

    它没有synchronize 关键字,但您可以通过Monitor 类获得非常相似的东西。下面是 Programming Ruby 1.8 书中的一个示例:

    require 'monitor'
    
    class Counter < Monitor
      attr_reader :count
      def initialize
        @count = 0
        super
      end
    
      def tick
        synchronize do
          @count += 1
        end
      end
    end
    
    c = Counter.new
    t1 = Thread.new { 100_000.times { c.tick } }
    t2 = Thread.new { 100_000.times { c.tick } }
    t1.join; t2.join
    c.count → 200000
    

    【讨论】:

    • 顺便说一句,这是一个通用的编程语言设计原则:只有蹩脚的编程语言才需要关键字或新的语言特性。精心设计的语言可以简单地在库中完成。
    • 如果你不想,你也不必从 Monitor 继承。只需将 MonitorMixin 模块(也由 require 'monitor' 引入)包含在您的课程中,您就可以免费获得相同的行为。
    • @JörgWMittag 看起来我们找到了一个 LISP 程序员 ;)
    • 我只是注释掉synchronize do,答案还是一样:200_000。诀窍在哪里?
    • 我添加了另一个答案,并解释了synchronize 的工作原理。 stackoverflow.com/a/30840316/1698467希望能有所帮助。
    【解决方案2】:

    接受的答案并不代表synchronize 的工作原理!

    您可以注释掉 synchronize do 并运行已接受答案的脚本 - 输出将是相同的:200_000

    所以,这里有一个例子,来展示使用/不使用synchronize 块运行之间的区别:

    非线程安全示例:

    #! /usr/bin/env ruby
    
    require 'monitor'
    
    class Counter < Monitor
      attr_reader :count
      def initialize
        @count = 0
        super
      end
    
      def tick i
        puts "before (#{ i }): #{ @count }"
        @count += 1
        puts "after (#{ i }): #{ @count }"
      end
    end
    
    c = Counter.new
    
    3.times.map do |i|
      Thread.new do
           c.tick i
      end
    end.each(&:join)
    puts c.count
    

    在输出中你会得到类似的东西:

    before (1): 0
    after (1): 1
    before (2): 0
    before (0): 0 <- !!
    after (2): 2
    after (0): 3 <- !!
    Total: 3
    

    当线程(0)启动时,count等于0,但添加+1后其值为3

    这里发生了什么?

    当线程启动时,它们会看到 count 的初始值。但是当他们每个人都尝试添加+1时,由于并行计算,值变得不同。如果没有适当的同步,count 的部分状态是不可预测的。

    原子性

    现在我们将这些操作称为原子

    #! /usr/bin/env ruby
    
    require 'monitor'
    
    class Counter < Monitor
      attr_reader :count
      def initialize
        @count = 0
        super
      end
    
      def tick i
        synchronize do
          puts "before (#{ i }): #{ @count }"
          @count += 1
          puts "after (#{ i }): #{ @count }"
        end
      end
    end
    
    c = Counter.new
    
    3.times.map do |i|
      Thread.new do
           c.tick i
      end
    end.each(&:join)
    puts c.count
    

    输出:

    before (1): 0
    after (1): 1
    before (0): 1
    after (0): 2
    before (2): 2
    after (2): 3
    Total: 3
    

    现在,通过使用synchronize 块,我们确保了添加操作的原子性

    但线程仍以随机顺序运行 (1->0->2)

    详细解释,您可以继续阅读this article

    【讨论】:

      猜你喜欢
      • 2010-12-31
      • 1970-01-01
      • 1970-01-01
      • 2010-11-14
      • 2023-03-17
      • 1970-01-01
      相关资源
      最近更新 更多