为什么这些线程ActiveRecord查询并不会同时运行?

时间:2014-05-15 22:14:09

标签: mysql ruby-on-rails multithreading activerecord concurrency

我正在尝试了解生产中的问题,所以我将这个代码段放在dev中的控制器操作中进行测试:

start = Time.now
num_threads = 6
results = Queue.new
saved_results = []
threads = []
connections = []
semaphore = Mutex.new

# start threads
(1..num_threads).each do |i|
  threads << Thread.new do
    #semaphore.synchronize { connections << ActiveRecord::Base.connection } # for cleanup?

    #ActiveRecord::Base.connection.execute("select sleep(1.6);")   # runs sequentially
    sleep(1.6)                                                    # runs concurrently
    result = User.find_by_id(i)
    results << [i, result]
  end
end

# end option 1 - let everyone finish
threads.each(&:join)

# end option 2 - simulate early exit condition
#while saved_results.count < 3 do saved_results << results.pop end
#threads.each(&:exit)

# cleanup/close open connections?
#connections.select(&:active?).each(&:disconnect!)

elapsed = Time.now - start
render :text => [ elapsed.to_s, saved_results.size, results.size ].join(", ")

sleep(1.6)按预期大约1.6秒执行。

但是,ActiveRecord select sleep(1.6);需要6 * 1.6 = 9.6秒,尽管mysql控制台show processlist;显示为每个线程打开了独立连接*。

发生了什么事?为什么ActiveRecord查询不会同时运行?我也在生产控制台中体验过这一点。

我在config.threadsafe!设置了config/environment.rb。如果重要,我正在使用Rails 2.3。

*必须手动关闭这些连接?生产总是有很多无效的开放连接,导致Mysql::Error: Too many connections。我可能会将此问题作为另一个问题提交。

1 个答案:

答案 0 :(得分:0)

一些评论:

  • rails 2.3本身并不是真正的线程安全,因为它是3.x轨道。但对于这种情况,我认为并不重要。
  • 你应该至少使用ruby 1.9。 &#34;绿线&#34;在1.8中不是最佳的。虽然在红宝石1.9中踩踏仍然不是最佳,但它更好。对于真正的线程,你应该检查jruby或rubinius(没有GIL)。
  • 你应该使用mysql2宝石。 mysql gem在等待数据库响应时保留GIL。