1

我尝试了解在生产中的问题,所以我扔在开发的控制器操作中这个片段进行测试:为什么不能同时运行这些线程化的ActiveRecord查询?

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。我可能会提出这个问题作为另一个问题。

回答

0

一些言论:

  • 轨2.3本身AFAIK本身不是真正线程安全的,因为轨道3.X它。但对于这种情况,我认为并不重要。
  • 你应该至少使用ruby 1.9。 1.8中的“绿色线程”并不理想。虽然踩红宝石1.9仍然不是最佳的,但它更好。对于真正的线程,你应该检查出jruby或rubinius(没有GIL)。
  • 你应该使用mysql2宝石。 mysql gem在等待来自数据库的响应时保持GIL。
+0

刚刚用mysql2进行了测试,并且此示例正常工作。我最近遇到了另一个与半相关的问题:http://stackoverflow.com/questions/26001994和使用mysql2在那里没有帮助 – Kache

相关问题