是否可以确保线程代码在 Ruby 中没有副作用?

发布于 2024-12-11 10:39:23 字数 1036 浏览 0 评论 0原文

数据安全和 GIL 删除 提到,如果您不这样做如果没有安装巨型解释器锁,就会增加竞争条件的风险。该博客文章给出了以下示例:

# As noted in the blog post, this'll work correctly in MRI Ruby (1.8 or 1.9)
# but may or may not work correctly in Rubinius 2.0 or JRuby
@array, threads = [], []
4.times do
  threads << Thread.new { (1..100_000).each {|n| @array << n} }
end
threads.each{|t| t.join }
puts @array.size

我采取的使代码线程安全的一种方法是进行函数式编程,并且不要让线程内的代码修改未在线程内创建的对象/变量:

threads = 4.times.map do
  Thread.new do
    sub_array = []
    # Modifying sub_array is fine, because it was created by this thread
    (1..100_000).each {|n| sub_array << n}
    sub_array
  end
end
puts threads.map(&:value).flatten(1).size
# Or (and don't forget nil!)
# array = threads.map(&:value).flatten(1) ; nil
# puts array.size

是否可以指定不允许线程修改不“属于”它的对象/变量,如果修改则引发警告或异常?

假设线程代码没有执行任何异常病态的操作,例如调用 ObjectSpace.each_object

Data safety and GIL removal mentions that if you don't have the Giant Interpreter Lock in place, you increase the risk of race conditions. The blog post gave the following example:

# As noted in the blog post, this'll work correctly in MRI Ruby (1.8 or 1.9)
# but may or may not work correctly in Rubinius 2.0 or JRuby
@array, threads = [], []
4.times do
  threads << Thread.new { (1..100_000).each {|n| @array << n} }
end
threads.each{|t| t.join }
puts @array.size

One approach I'd take to making the code thread safe is to do functional programming and not have code within the thread modify objects/variables that weren't created within the thread:

threads = 4.times.map do
  Thread.new do
    sub_array = []
    # Modifying sub_array is fine, because it was created by this thread
    (1..100_000).each {|n| sub_array << n}
    sub_array
  end
end
puts threads.map(&:value).flatten(1).size
# Or (and don't forget nil!)
# array = threads.map(&:value).flatten(1) ; nil
# puts array.size

Is it possible to specify that a thread isn't allowed to modify objects/variables that don't "belong" to it, and raise a warning or exception if it does?

Assume that the threaded code doesn't do anything spectacularly pathological like calling ObjectSpace.each_object.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

世界和平 2024-12-18 10:39:23

除了创建独立的新进程的长期传统之外,我不知道有什么方法可以限制 Ruby 以任何身份访问事物。大多数语言都是这样的,只有极少数例外,正如您指出的那样,严格的函数式语言属于该集合。

这里最负责任的方法是使用互斥锁,或者通过保持数据隔离和独立来创建线程安全的类。这需要仔细设计,但如果做得正确,您的线程应用程序几乎与标准应用程序一样简单。

I don't know of a way to limit Ruby's access to things in any capacity other than the long-standing tradition of forking out a new process that is independent. Most languages are like this with very few exceptions, with strictly functional languages being in that set as you point out.

The most responsible approach here is to either use Mutex locking, or to create classes that are thread-safe by keeping data isolated and independent. This requires careful design, but if done right your threaded application is nearly as simple as a standard one.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文