gpt4 book ai didi

ruby - Ruby 中哈希的线程安全

转载 作者:数据小太阳 更新时间:2023-10-29 08:38:03 26 4
gpt4 key购买 nike

我很好奇 Ruby 中哈希的线程安全性。从控制台 (Ruby 2.0.0-p247) 运行以下命令:

h = {}
10.times { Thread.start { 100000.times {h[0] ||= 0; h[0] += 1;} } }

返回

{0=>1000000}

这是正确的期望值。

为什么有效?在这个版本的 Ruby 中,我可以依赖哈希是线程安全的吗?

编辑:测试 100 次:

counter = 0
100.times do
h={}
threads = Array.new(10) { Thread.new { 10000.times { h[0] ||= 0; h[0] += 1 } } }
threads.map { |thread| thread.join }
counter += 1 if h[0] != 100000
end
puts counter

计数器到最后还是0。我尝试了多达 10K 次,但从未遇到过此代码的线程安全问题。

最佳答案

不,您不能指望 Hashes 是线程安全的,因为它们不是为线程安全而构建的,很可能是出于性能原因。为了克服标准库的这些限制,创建了提供线程安全(concurrent-ruby)或不可变(hamster)数据结构的 Gems。这些将使访问数据线程安全,但除此之外,您的代码还有一个不同的问题:

您的输出将不是确定性的;事实上,我试过几次你的代码,结果是 544988。在您的代码中,经典的 race condition可能会发生,因为涉及单独的读取和写入步骤(即它们不是原子的)。考虑表达式 h[0] ||= 0, which basically translates to h[0] || h[0] = 0 .现在,很容易构造出现竞争条件的情况:

  • 线程1读取h[0]发现是nil
  • 线程2读取h[0],发现是nil
  • 线程 1 设置 h[0] = 0 并递增 h[0] += 1
  • 线程 2 设置 h[0] = 0 并递增 h[0] += 1
  • 生成的哈希值是 {0=>1},但正确的结果是 {0=>2}

如果你想确保你的数据不被破坏,你可以锁定操作with a mutex :

require 'thread'
semaphore = Mutex.new

h = {}

10.times do
Thread.start do
semaphore.synchronize do
100000.times {h[0] ||= 0; h[0] += 1;}
end
end
end

注意:此答案的早期版本提到了“thread_safe”gem。 “thread_safe”自 2017 年 2 月起已弃用,成为“concurrent-ruby”gem 的一部分。改用那个。

关于ruby - Ruby 中哈希的线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22674498/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com