I18n.with_locale 线程安全吗?

5

我创建了一个功能,可以发布一条新闻,并使用页面创建者的语言。

以下是创建新闻的代码:

def add_news
  locale = creator.language.blank? ? I18n.locale : creator.language
  I18n.with_locale(locale) do
    title = I18n.t('news.subject')
  end
  create_news({title: title})
end

这个功能很好用,新闻使用的语言非常不错。但有时会使用错误的语言。我已经阅读了i18n的源代码(https://github.com/svenfuchs/i18n/blob/master/lib/i18n.rb),对我来说,with_local函数不是线程安全的。我感到非常惊讶,因为我没有看到任何关于这个问题的帖子。

那么,你认为这个功能是否线程安全?如果不是,你知道其他解决方案吗?

谢谢,祝好

Eric

2个回答

3

看起来这段内容是关于Ruby on Rails指南的,因为它使用了Thread.current。

还进行了一个小型(有结论)的实验:

n = I18n.available_locales.length
10.times do |i|
  loc = I18n.available_locales[i % n]
  Thread.new do
    I18n.with_locale(loc) do
      puts "#{loc} #{I18n.t 'one.of.your.keys'}"
    end
  end
end

值得注意的是,这是一个不典型场景的模拟。Rails的I18n模块存在线程安全问题的原因是,在使用像Puma或Thin这样的多线程Web服务器时,它允许在请求之间泄漏状态。下面@stevepentler的回答进行了澄清。 - Jake Romer

1

Thread.current 对于像 Puma 或 Thin 这样的多线程 Web 服务器来说不是线程安全的。详细解释请参见 github.com/steveklabnik/request_store

问题

现在人们都担心并发性能,所以使用那些时髦的多线程 Web 服务器,如 Thin 或 Puma。但是如果您使用 Thread.current 并且使用其中之一的服务器,请注意!值可能会比您预期的更长时间保留,这可能会导致错误。例如,如果我们在控制器中有这个:

  def index   
    Thread.current[:counter] ||= 0   
    Thread.current[:counter] += 1
    render :text => Thread.current[:counter]
  end

如果我们在MRI和Webrick上运行它,每次输出都会是1。但是如果你用Thin运行它,你会得到1、2、3……的输出。

这并不意味着Thread.current不是线程安全的。它是线程安全的,因为每个线程都有自己的哈希值,t个线程将不会看到或写入彼此的数据。它不是PER REQUEST,这可能是您正在努力实现的内容。因此,Puma和Thin的行为是完全符合预期的。话虽如此,我不知道为什么Webrick会在每个请求中清除Thread.current。 - Jack Casey

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