Ruby:内存中基于哈希的线程安全缓冲区?

Ruby:内存中基于哈希的线程安全缓冲区?,ruby,thread-safety,queue,buffer,Ruby,Thread Safety,Queue,Buffer,我正在Redis支持的库中实现一种写/存储缓冲区,将多个hincrby调用压缩为一个调用。缓冲区需要完全原子化,并跨多个线程工作 因此,我对处理线程安全性非常陌生;是否有任何现有的库或标准化的方法来实现在线程环境中运行良好的基于全局哈希的缓冲区/队列 例如,缓冲区哈希的工作原理类似于以下伪代码: buffer #=> { :ident1 => { :value_a => 1, :value_b => 4 }, # :ident2 => { :v

我正在Redis支持的库中实现一种写/存储缓冲区,将多个
hincrby
调用压缩为一个调用。缓冲区需要完全原子化,并跨多个线程工作

因此,我对处理线程安全性非常陌生;是否有任何现有的库或标准化的方法来实现在线程环境中运行良好的基于全局哈希的缓冲区/队列

例如,缓冲区哈希的工作原理类似于以下伪代码:

buffer #=> { :ident1 => { :value_a => 1, :value_b => 4 },
       #     :ident2 => { :value_a => 2, :value_b => 3 } }

buffer[:ident1][:value_a] #=> 1

# saving merges and increments {:value_a => 2} into buffer[:ident1]
save(:ident1, {:value_a => 2})

buffer[:ident1][:value_a] #=> 3

其思想是,在X次
save
调用后,通过调用
save
来刷新缓冲区。通常,以线程安全的方式提供对全局值的访问的方法是使用内置互斥类:

$buffer = {}
$bufflock = Mutex.new

threads = (0..2).map do |i|
  Thread.new do
    puts "Starting Thread #{i}"
    3.times do
      puts "Thread #{i} got: #{$buffer[:foo].inspect}"
      $bufflock.synchronize{ $buffer[:foo] = ($buffer[:foo] || 1) * (i+1) }
      sleep rand
    end
    puts "Ending Thread #{i}"
  end
end
threads.each{ |t| t.join } # Wait for all threads to complete

#=> Starting Thread 0
#=> Thread 0 got: nil
#=> Starting Thread 1
#=> Thread 1 got: 1
#=> Starting Thread 2
#=> Thread 2 got: 2
#=> Thread 1 got: 6
#=> Thread 1 got: 12
#=> Ending Thread 1
#=> Thread 0 got: 24
#=> Thread 2 got: 24
#=> Thread 0 got: 72
#=> Thread 2 got: 72
#=> Ending Thread 0
#=> Ending Thread 2
块内的代码是每个线程的原子代码;在前一个线程处理完块之前,一个线程不能进入
$bufflock


另请参见:

通常,以线程安全的方式提供对全局值的访问的方法是使用内置的互斥类:

$buffer = {}
$bufflock = Mutex.new

threads = (0..2).map do |i|
  Thread.new do
    puts "Starting Thread #{i}"
    3.times do
      puts "Thread #{i} got: #{$buffer[:foo].inspect}"
      $bufflock.synchronize{ $buffer[:foo] = ($buffer[:foo] || 1) * (i+1) }
      sleep rand
    end
    puts "Ending Thread #{i}"
  end
end
threads.each{ |t| t.join } # Wait for all threads to complete

#=> Starting Thread 0
#=> Thread 0 got: nil
#=> Starting Thread 1
#=> Thread 1 got: 1
#=> Starting Thread 2
#=> Thread 2 got: 2
#=> Thread 1 got: 6
#=> Thread 1 got: 12
#=> Ending Thread 1
#=> Thread 0 got: 24
#=> Thread 2 got: 24
#=> Thread 0 got: 72
#=> Thread 2 got: 72
#=> Ending Thread 0
#=> Ending Thread 2
块内的代码是每个线程的原子代码;在前一个线程处理完块之前,一个线程不能进入
$bufflock


另请参见:

一个可能有用的非答案:您是否有客观理由(即测量)相信向异步系统添加同步瓶颈将提高性能?您计划在哪个Ruby版本和VM上运行此功能?(MRI、JRuby、Rubinius、IronRuby等?)Rein:写缓冲区旨在通过将多个hincrby调用合并为一个来减少Redis服务器本身的负载。目前,我们平均每秒约25000个请求关闭了Redis服务器。大约38k/秒的Redis成为了瓶颈。Phrogz:它的目的是进入一个gem,所以一般的想法是它至少会在MRI 1.8/1.9和JRuby上运行。一个潜在的有用的非答案是:你有客观原因(即测量)吗相信向异步系统添加同步瓶颈将提高性能吗?您计划在哪个Ruby版本和VM上运行此功能?(MRI、JRuby、Rubinius、IronRuby等?)Rein:写缓冲区旨在通过将多个hincrby调用合并为一个来减少Redis服务器本身的负载。目前,我们平均每秒约25000个请求关闭了Redis服务器。大约38k/秒的Redis成为了瓶颈。Phrogz:它的目的是进入一个gem,所以一般的想法是它至少会在MRI 1.8/1.9和JRuby上运行。谢谢,换言之,使用互斥器/监视器似乎是一种方式。我不确定是否有任何具体的最佳实践可以遵循,或者需要注意的陷阱:)谢谢,换言之,使用互斥体/监视器似乎是一种方法。我不确定是否有任何具体的最佳实践可以遵循,或者是否有陷阱需要注意:)