Ruby on rails Rails 4-线程错误

Ruby on rails Rails 4-线程错误,ruby-on-rails,Ruby On Rails,我正在尝试执行一些计算,以填充数据库中的一些历史数据 数据库是SQL Server。服务器是tomcat(使用JRuby) 我正在一个指向uat环境的rails控制台中运行脚本文件 我正在尝试使用线程来加速执行。其思想是,每个线程将获取一个对象并为其运行计算,然后将计算出的值保存回数据库 问题:我经常遇到以下错误: ActiveRecord::ConnectionTimeoutError (could not obtain a database connection within 5.000 s

我正在尝试执行一些计算,以填充数据库中的一些历史数据

数据库是SQL Server。服务器是tomcat(使用JRuby)

我正在一个指向uat环境的rails控制台中运行脚本文件

我正在尝试使用线程来加速执行。其思想是,每个线程将获取一个对象并为其运行计算,然后将计算出的值保存回数据库

问题:我经常遇到以下错误:

ActiveRecord::ConnectionTimeoutError (could not obtain a database connection within 5.000 seconds (waited 5.000 seconds))
代码:

需要“线程”
线程=[]
items_to_calculate=Item.where(“id<11”)。to_a#目前只测试10项
对于要计算的项目中的项目

线程如果离开测试阶段,您可能同时启动大量线程

每个线程都需要一个DB连接。Rails可能会为每个线程创建一个新的连接(可能会同时创建大量的DB连接),也可能不会,在这种情况下,您会遇到麻烦,因为多个线程试图并行使用同一个连接。第一种情况将解释错误消息,因为您的DB服务器中可能存在开放DB连接的硬限制

创建这样的线程通常是不可取的。通常,最好创建少量(受控/有限)的工作线程,并使用队列在它们之间分配工作


在您的例子中,您可以有一组工作线程来进行计算,还有一组工作线程来写入数据库。我对代码的细节了解不够,无法为您决定哪种更好。如果计算成本很高,而数据库的工作成本却很低,那么您可能只有一个工作线程以串行方式写入数据库。如果您的数据库是一个野兽,并且针对并行写入进行了高度优化,并且您需要写入大量数据,那么您可能需要(少量)的数据库工作线程。

如果您离开测试阶段,您可能同时启动大量线程

每个线程都需要一个DB连接。Rails可能会为每个线程创建一个新的连接(可能会同时创建大量的DB连接),也可能不会,在这种情况下,您会遇到麻烦,因为多个线程试图并行使用同一个连接。第一种情况将解释错误消息,因为您的DB服务器中可能存在开放DB连接的硬限制

创建这样的线程通常是不可取的。通常,最好创建少量(受控/有限)的工作线程,并使用队列在它们之间分配工作


在您的例子中,您可以有一组工作线程来进行计算,还有一组工作线程来写入数据库。我对代码的细节了解不够,无法为您决定哪种更好。如果计算成本很高,而数据库的工作成本却很低,那么您可能只有一个工作线程以串行方式写入数据库。如果您的数据库是一个野兽,并且针对并行写入进行了高度优化,并且您需要写入大量数据,那么您可能需要(少量)的数据库工作线程。

您可能会产生比ActiveRecord的数据库连接池有连接的线程更多的线程。是一个很好的概括描述;下面是一个简单的示例,说明如何使用Ruby的线程安全
队列
限制工作人员

require 'thread'

queue = Queue.new
items.each { |i| queue << i } # Fill the queue

Array.new(5) do # Only 5 concurrent workers
  Thread.new do
    until queue.empty?
      item = queue.pop
      ActiveRecord::Base.connection_pool.with_connection do
        # Work
      end
    end
  end
end.each(&:join)
需要“线程”
queue=queue.new

items.each{| i | queue您生成的线程可能比ActiveRecord的DB连接池的连接数量还要多。这是一个很好的一般性描述;下面是一个简单的示例,说明如何使用Ruby的线程安全
queue
来限制工作人员

require 'thread'

queue = Queue.new
items.each { |i| queue << i } # Fill the queue

Array.new(5) do # Only 5 concurrent workers
  Thread.new do
    until queue.empty?
      item = queue.pop
      ActiveRecord::Base.connection_pool.with_connection do
        # Work
      end
    end
  end
end.each(&:join)
需要“线程”
queue=queue.new

每项{| i | queue我想说计算没有执行,因为他们在字符串上使用eval来计算公式,也在使用BigDecimal。calculate|u details方法可以执行30-40个计算。你能给出一个代码示例吗?我想说计算没有执行,因为他们在字符串上使用eval来计算公式,以及使用BigDecimal。calculate_details方法可以执行30-40次计算。您可以发布一个代码示例吗?谢谢,我该如何做“工作”并传入我的项目?已存在
项目
-请参阅
项目=队列。pop
?块可以访问在其词法范围中定义的变量。谢谢,我在发表评论后通知了这一点。我更改了代码,但仍然出现超时错误。如果需要,我可以发布我的全部代码,尝试从1个线程开始并使用您的直到你找到一个限制。如果你的应用程序中有其他事情发生,你可能无法访问整个池。如果这仍然不起作用,请尝试用工作结果填充第二个
队列
,然后在所有事情完成后以串行方式保存你的项目。这很奇怪。如果没有访问整个应用程序的权限,我无法调试,但是不要尝试剥离数组和线程包装器,只处理队列而不进行任何并发。如果仍然失败,则会发生其他事情-可能在
ItemCalculator
中?谢谢,我该如何做“工作”并传入我的项目?已存在
项目
-请参阅
项目=队列。pop
?块可以访问在其词法范围中定义的变量。谢谢,我在发表评论后通知了这一点。我更改了代码,但仍然出现超时错误。如果需要,我可以发布我的全部代码,尝试从1个线程开始并使用您的直到你找到一个限制。如果你的应用程序中有其他事情发生,你可能无法访问整个池。如果这仍然不起作用,请尝试用工作结果填充第二个
队列
,然后在所有事情完成后以串行方式保存你的项目。这很奇怪。没有访问权限我无法调试