lon*_* ma 1 ruby multithreading thread-safety
代码片段:
a = 0
Array.new(50){
Thread.new {
500_000.times { a += 1 }
}
}.each(&:join)
p "a: #{a}"
Run Code Online (Sandbox Code Playgroud)
结果:a = 25_000_000。
据我了解,(MRI) Ruby 使用 GIL,所以只有一个 ruby 线程可以获得 CPU,但是当发生线程切换时,会存储一些 ruby 线程的数据,以便稍后恢复线程。所以,理论上,a += 1可能不是线程安全的。
但上面的结果证明我错了。Ruby 是否具有a+=1原子性?如果为真,哪些操作可以被认为是线程安全的?
在您的示例中,明显的一致性主要是由于全局解释器锁,但也部分是由于您的 Ruby 引擎和您的代码序列(理论上)异步线程的方式。你得到一致的结果,因为在每个线程的每个循环简单地增加的当前值一,这是不是一个块本地或线程局部变量。随着YARV虚拟机上线,在同一时间只有一个线程检查或设定的电流值一个,但我真的不能说,它是一个原子操作。这只是引擎缺乏线程间实时并发性和Ruby虚拟机底层实现的副产品。
如果您担心在 Ruby 中保留线程安全性而不依赖于恰好看起来一致的特殊行为,请考虑使用诸如concurrent-ruby 之类的线程安全库。否则,您可能会依赖 Ruby 引擎或 Ruby 版本无法保证的行为。
例如,在JRuby的代码(这三个连续的运行确实有并发线程)一般产生在每次运行时不同的结果。例如:
#=> "a: 3353241"#=> "a: 3088145"#=> "a: 2642263"| 归档时间: |
|
| 查看次数: |
111 次 |
| 最近记录: |