我有一個名為 AisSignal 的模型,其中包含大約 3000 條記錄,并且我正在針對另一個名為 Footprint 的模型運行每個模型,其中包含大約 10 條記錄,因此我們有一個 3000 x 10 的回圈。
我試過了:
Parallel.each(AisSignal.all, in_processes: 8) do |signal|
Footprint.all.each do |footprint|
if footprint.cover([signal.lon, signal.lat])
signal.update(imo: 'in')
break
end
end
end
但它像普通塊一樣在 10 秒內運行。
我試圖從行程更改為如下所示的執行緒,但這會導致應用程式凍結。
Parallel.each(AisSignal.all, in_threads: 8) do |signal|
Footprint.all.each do |footprint|
if footprint.cover([signal.lon, signal.lat])
signal.update(imo: 'in')
break
end
end
end
我在 database.yml 中有 50 個池大小
讓多個執行緒并行運行以更新記錄的任何想法或方法。實際上,我需要更新更多記錄,這可能需要幾分鐘。
uj5u.com熱心網友回復:
執行緒和分叉通常不能很好地處理資料庫連接。如果處理不當,執行緒/行程可能會嘗試同時使用相同的連接。
Parallel 在他們的檔案中提到了這一點。您需要使用連接池。
連接池將執行緒訪問同步到有限數量的資料庫連接。基本思想是每個執行緒從池中檢出一個資料庫連接,使用該連接,然后再檢查該連接。 ConnectionPool 是完全執行緒安全的,將確保一個連接不能被兩個執行緒同時使用,只要正確遵循 ConnectionPool 的合同。它還將處理執行緒多于連接的情況:如果所有連接都已簽出,并且一個執行緒無論如何都嘗試簽出一個連接,那么 ConnectionPool 將等待,直到某個其他執行緒簽入一個連接。
Parallel.each(AisSignal.all, in_threads: 8) do |signal|
ActiveRecord::Base.connection_pool.with_connection do
Footprint.all.each do |footprint|
if footprint.cover([signal.lon, signal.lat])
signal.update(imo: 'in')
break
end
end
end
end
請注意,此代碼效率非常低。
- 它加載整個
AisSignal表。 - 對于每個信號,它都會加載并掃描整個
Footprint表。
它將使用大量記憶體,并且它將在 s*f 時間內運行,其中s是信號f數,是足跡數。
Footprint.all.each您可以通過替換為來減少記憶體占用Footprint.find_each。這將分批加載行。
執行緒不是使資料庫查詢更快的方法。根本問題是您在 Ruby 中多次掃描足跡,而不是讓資料庫來做。if footprint.cover([signal.lon, signal.lat])應該改為 where 子句。
AisSignal.find_each do |signal|
# With ... being the equivalent of `cover([signal.lon, signal.lat])`
# as a where clause.
signal.update!(imo: 'in') if Footprint.exists?(...)
end
作為連接,這可以更快地完成。
# ... is the equivalent of `cover([signal.lon, signal.lat])`
AisSignal.joins("inner join footprints on ...").update_all(imo: 'in')
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/440710.html
標籤:轨道上的红宝石 红宝石 PostgreSQL 并行处理
上一篇:正確更新其他列的更新列
下一篇:根據該陣列中的元素對陣列進行排序
