修改线程之间公共哈希的不同密钥是否安全?

时间:2019-07-05 08:53:45

标签: ruby concurrency

在线程之间共享Ruby哈希并在每个线程中对其进行修改是否是线程安全的,并确保每个线程修改不同的密钥(在执行之前,在未确定的情况下将新的哈希附加到其密钥数目) ?

我知道,如果线程修改了相同的密钥,那么这样做不是线程安全的。但是,我不确定如果它们修改了不同的密钥是否安全。

例如下面是一个示例程序,可能说明了问题:

#!/usr/bin/env ruby
# frozen_string_literal: true

array = [*1..100]
hash = {}
array.each do |element|
    hash[element] = {}
end
threads = []
array.each do |element|
    threads << Thread.new do
        random = rand(1..100)
        hash_new_keys = [*0..random]
        hash[element] = {}
        hash_new_keys.each do |key|
            hash[element][key] = rand(1..10)
        end
    end
end
threads.each(&:join)

1 个答案:

答案 0 :(得分:3)

如果使用MRI,则其线程安全,可修改不同线程中的数组/哈希。 GIL保证同时只有一个线程处于活动状态。

这里有5个线程共享一个Array对象。每个线程将nil压入数组1000次:

array = []

5.times.map do
  Thread.new do
    1000.times do
      array << nil
    end
  end
end.each(&:join)

puts array.size


$ ruby pushing_nil.rb
5000

$ jruby pushing_nil.rb
4446

$ rbx pushing_nil.rb
3088
  

由于MRI具有GIL,即使一次运行5个线程,   一次仅一个线程处于活动状态。换句话说,事情不是   真正的平行。 JRuby和Rubinius没有GIL,所以当您有   5个线程在运行,您实际上有5个线程在并行运行   跨可用核心。

     

在并行Ruby实现中,5个线程正在逐步执行   通过不是线程安全的代码。他们最终打断了每个人   其他,并最终破坏基础数据。

参考https://www.jstorimer.com/blogs/workingwithcode/8085491-nobody-understands-the-gil