繁体   English   中英

Rails 4.2:如何动态更改线程使用的连接?

[英]Rails 4.2: How to dynamically change the connection used by a thread?

如何更改一个线程的连接? 我想这样做:

# slow query process at background
Thread.new do
  User.all { |user| user.update_attributes(some_field: (rand * 100).to_i) }
end

# more slow query process
100000.times { User.where(some_field_2: (rand * 100).to_i).first }

我希望这两个线程(主线程和我创建的线程)异步运行,但我发现 Rails 使用一个连接来执行此操作。 因此,我同时运行 2 个查询并获得时间的所有努力都被破坏了 - Rails 将我的请求缩减到 1 个单一和同步池中。 我也尝试过以下方法,但尽管 Rails 创建了一个新连接,但 ActiveRecord(“用户”)并没有使用它:

# slow query process at background
Thread.new do
  conn = ActiveRecord::Base.connection_pool.checkout()
  User.all {|user| user.update_attributes(some_field: (rand * 100).to_i) }
  ActiveRecord::Base.connection_pool.checkin(conn)
end

我曾尝试设置“ActiveRecord::Base.connection = conn”但也没有用。

有可能每个线程都有自己的连接吗? 如何设置螺纹连接?

根据rails guide ,您必须将应用程序代码包装在执行程序块中。

试试这个(对于 Rails 版本:4):

Thread.new do
  ActiveRecord::Base.connection_pool.with_connection do
    User.all { |user| user.update_attributes(some_field: (rand * 100).to_i) }
  end
end

# more slow query process
100000.times { User.where(some_field_2: (rand * 100).to_i).first }

假设config/database.yml池大小值大于 1,这应该可以工作。

好,我知道了。 但是我必须对“retrieve_connection”进行一些修改才能实现这一点。 我把它放在我的 application.rb 上:

module ActiveRecord
  module ConnectionAdapters
    class ConnectionHandler
      def retrieve_connection(klass) #:nodoc:
        pool = retrieve_connection_pool(klass)
        raise ConnectionNotEstablished, "No connection pool for #{klass}" unless pool
        conn = Thread.current["connection"] || pool.connection
        raise ConnectionNotEstablished, "No connection for #{klass} in connection pool" unless conn
        conn
      end
    end
  end
end

我只是将“conn = pool.connection”修改为“conn = Thread.current[“connection”] || pool.connection”。 这允许我使用自定义线程变量定义连接。 有了这个 hack,我的代码看起来像这样:

# slow query process at background
Thread.new do
  Thread.current["connection"] = ActiveRecord::Base.connection_pool.checkout()
  User.all {|user| user.update_attributes(some_field: (rand * 100).to_i) }
  ActiveRecord::Base.connection_pool.checkin(Thread.current["connection"])    
end

# more slow query process
100000.times { User.where(some_field_2: (rand * 100).to_i).first }

或者更好的是,为每次更新创建一个新线程:

# slow query process at background
User.all do |user|
  Thread.new do
    Thread.current["connection"] = ActiveRecord::Base.connection_pool.checkout()
    user.update_attributes(some_field: (rand * 100).to_i)
    ActiveRecord::Base.connection_pool.checkin(Thread.current["connection"])
  end
end

# more slow query process
100000.times { User.where(some_field_2: (rand * 100).to_i).first }

PS:这满足了我的需求,但是我想知道是否有更改线程连接的本机方法。 我做的方式太丑了:/所以,如果你知道更好的方法,请分享。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM