在Ruby中,是否可以跨线程共享数据库连接?

时间:2013-12-03 06:14:30

标签: ruby multithreading heroku

我有一个小小的红宝石脚本,可以播放超过80,000张左右的唱片 每个记录所涉及的处理器和内存负载小于smurf球,但是所有记录仍然需要大约8分钟。

我想使用线程,但是当我放弃它时,我的数据库耗尽了连接。当然,当我试图连接200次时,我真的可以限制它比那更好..但是当我把这个代码推到Heroku(我有20个连接供所有工人分享)时,我不知道想要阻止其他进程,因为这个进程增加了。

我已经考虑过重构代码以便它能够连接所有的SQL,但这会让人觉得非常混乱。

所以我想知道是否有让线程共享连接的技巧?鉴于我不希望连接变量在处理期间发生变化,我实际上对线程分叉需要创建新的数据库连接感到惊讶。

任何帮助都会非常酷(就像我一样)..谢谢

<小时/> SUPER CONTRIVED 示例
以下是100%做作的例子。它确实显示了问题 我在一个非常简单的线程中使用ActiveRecord。似乎每个线程都在创建它自己与数据库的连接。我将此假设基于随后的警告消息。

START_TIME = Time.now

require 'rubygems'
require 'erb'
require "active_record"

@environment = 'development'
@dbconfig = YAML.load(ERB.new(File.read('config/database.yml')).result)
ActiveRecord::Base.establish_connection @dbconfig[@environment]

class Product < ActiveRecord::Base; end

ids = Product.pluck(:id)
p "after pluck #{Time.now.to_f - START_TIME.to_f}"

threads = [];
ids.each do |id|
  threads << Thread.new {Product.where(:id => id).update_all(:product_status_id => 99); }
  if(threads.size > 4)
    threads.each(&:join)
    threads = [] 
    p "after thread join #{Time.now.to_f - START_TIME.to_f}"
  end
end

p "#{Time.now.to_f - START_TIME.to_f}"

输出

"after pluck 0.6663269996643066"
DEPRECATION WARNING: Database connections will not be closed automatically, please close your
database connection at the end of the thread by calling `close` on your
connection.  For example: ActiveRecord::Base.connection.close
. (called from mon_synchronize at /Users/davidrawk/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/1.9.1/monitor.rb:211)
.....
"after thread join 5.7263710498809814"   #THIS HAPPENS AFTER THE FIRST JOIN.
.....
"after thread join 10.743254899978638"   #THIS HAPPENS AFTER THE SECOND JOIN

1 个答案:

答案 0 :(得分:2)

请参阅此gem https://github.com/mperham/connection_pool并回答,您可能需要连接池:Why not use shared ActiveRecord connections for Rspec + Selenium?

另一种选择是使用https://github.com/eventmachine/eventmachine并在EM.defer块中运行您的任务,以便以非阻塞方式在回调块(在reactor内)进行数据库访问

或者,也是一个更强大的解决方案,请使用轻量级后台处理队列,例如beanstalkd,有关更多选项,请参阅https://www.ruby-toolbox.com/categories/Background_Jobs - 这将是我的主要建议

EDIT,

另外,您可能没有200个内核,因此创建200多个并行线程和数据库连接并不会真正加快进程(实际减慢速度),看看是否可以找到一种方法将问题划分为许多集合等于你的核心数+ 1并以这种方式解决问题,

这可能是解决问题的最简单方法

相关问题