gpt4 book ai didi

multithreading - Rails 4.2自动加载不是线程安全的

转载 作者:行者123 更新时间:2023-12-04 03:50:59 24 4
gpt4 key购买 nike

我有以下模型:

class User < ActiveRecord::Base
def send_message(content)
MessagePoro.new(content).deliver!
end

def self.send_to_all(content)
threads = []
all.each do |user|
threads << Thread.new do
user.send_message(content)
end
end
threads.each(&:join)
end
end

MessagePoro 模型可以很简单,例如应用程序/模型/message_poro.rb:
class MessagePoro
def initialize(content)
# ...
end

def deliver!
# ...
end
end

现在,当我有例如100 个用户,我正在运行 User.send_to_all("test") 我是 有时得到那些错误:
RuntimeError: Circular dependency detected while autoloading constant MessagePoro

或者:
wrong number of arguments (1 for 0)

我想这一定是因为没有加载 MessagePoro 并且所有线程都尝试同时加载它,或者类似的东西。由于这些错误仅在某些时候发生,我很确定只有在存在“竞争条件”或与线程有关的情况下才会发生。我曾尝试在启动 Threads 之前初始化 MessagePoro,并且我玩过 eager_loading,但问题似乎仍然存在。
我还能尝试什么来缓解这个问题?

最佳答案

我最近在尝试使用放置在 [rails_root]/lib 中的额外自定义库时遇到了一个非常相似的问题。目录。

TL;博士:

您可以使用急切加载来解决此问题,因为这样可以确保所有常量/模块/类在任何实际代码运行之前都在内存中。然而,为了这个工作:

  • 您必须拥有 config.eager_load = true在 Rails 配置中设置(在生产环境中默认设置)
  • 你的class-to-be-eager-loaded所在的文件必须在config.eager_load_paths ,而不是 config.autoload_paths .

  • 或者

    您可以使用 requirerequire_dependency (另一个 ActiveSupport 功能)以确保在 Rails 自动加载之前显式加载您需要的代码。

    更多信息

    正如 digidigo 在他的回复中提到的,循环依赖错误来自 ActiveSupport::Dependencies模块,或 Rails 自动加载器 更笼统地说。此代码为 不是线程安全的 ,因为它使用该类/模块变量来存储它正在加载的文件。如果两个线程最终同时自动加载相同的东西,其中一个线程可能会因为看到要在该类变量中加载的文件并引发“循环依赖”错误而被误导。

    我在使用(线程)Puma 网络服务器在生产模式下运行 Rails 时遇到了这个问题。我们在 lib 中添加了一个小型库。在我们的 Rails 根目录中,最初添加了 libconfig.autoload_once_paths .在开发中一切都很好,但在生产中(启用 config.eager_loadconfig.cache_classes),我们偶尔会在几乎同时请求的情况下遇到这些相同的循环依赖问题。几个小时后的调试,当我围绕循环依赖单步执行 ActiveSupport 代码并看到不同线程在代码中的不同点启动时,我最终看到了在我眼前发生的非线程安全。第一个线程会将要加载的文件添加到 loading数组,然后第二个线程会在那里找到它并引发循环依赖错误。

    结果是向 autoload_paths 添加了一些东西或 autoload_once_paths也不意味着它会被急切的加载拾取。然而,情况恰恰相反——添加到 eager_load_paths 的路径如果 eager_load 被禁用,将考虑自动加载(参见 this article 了解更多信息)。我们切换到 eager_load_paths并且到目前为止没有进一步的问题。

    有趣的是,就在 Rails 4 测试版之前,生产环境中默认禁用自动加载,这意味着像这样的问题会导致 100% 的时间发生硬故障,而不是 5% 的时间导致古怪的线程失败.然而,这在 4.0 beta 版本中被及时恢复了——你可以看到一些关于它的(热情的)讨论 here (包括选择短语“老实说,你是在告诉我自己去他妈的?”)。不过,从那时起,该恢复已在 Rails 5.0.0beta1 之前恢复,因此希望将来有更少的人需要再次处理这个令人头疼的问题。

    额外说明:

    Rails 自动加载器与 Ruby 自动加载器完全分离——这似乎是因为 Rails 在尝试自动加载常量时对目录结构进行了更多推断。

    自 Ruby 2.0 起,Ruby 的自动加载似乎已成为线程安全的,但这与 Rails 自动加载代码无关。 Rails 的自动加载器似乎肯定是 不是 线程安全,如前所述。

    关于multithreading - Rails 4.2自动加载不是线程安全的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29439323/

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