在Rails操作中使用Thread.new

3

在使用多进程应用服务器并在控制器操作中运行Thread.new(生成多个线程)时,是否实现了并行处理?还是GIL阻止了这种情况的发生?

2个回答

7
全局解释器锁(GIL)防止多个Ruby线程在任何给定时间运行,从而限制Ruby只能使用一个核心。除此之外,它们是实际的线程。
如果您需要真正的并发性,您需要运行没有GIL的Ruby,如JRuby。
话虽如此,在Ruby中,线程对于许多操作都很好,其中您没有钉住CPU核心。如果您这样做,应该通过ActiveJob创建后台作业来执行这些操作。如果必要,这些作业可以在不同系统上的一个或多个进程中运行。

4

@tadman的回答完全正确,我只想在第三段稍微扩展一下。

何时在MRI Ruby中使用线程是一个好的选择?通常情况下,如果您受到IO操作的限制,那么线程就很有用。因此,如果您有一个Rails动作,其中包含许多数据库查询和/或http请求,您可以将它们放入一个Thread中,在Thread本地变量中安全地进行请求,然后将它们合并,并处理线程本地变量。这样,您将实现明显的性能改进。

可能看起来像这样:

threads << Thread.new do
  ActiveRecord::Base.connection_pool.with_connection do
  t = Thread.current
  t[:variable_name] = Model.find_by(col: data)
  end
end
joined_threads = threads.map &:join
joined_threads.each do |t|
  t.keys.each do |key|
    k = key.to_s.downcase
    next if k.start_with?("active") || k.start_with?("__")
    instance_variable_set "@#{key}", t[key]
  end
end

谢谢提供详细信息!但我不明白这如何规避GIL防止多线程同时运行的问题? - mstrom
1
@mstrom 很抱歉之前没有回复你。我写了一篇博客文章,将解答你的问题。这是链接: https://link.medium.com/RCMyp9fiiX - Shimu
在“Rails自动包装Web请求和Active Job工作程序”的情况下,是否需要使用with_connection?https://guides.rubyonrails.org/threading_and_code_execution.html#reloader - John Bachir

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接