簡體   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