2013-12-03 4 views
0

У меня есть небольшой маленький рубиновый скрипт, в котором записано более 80 000 записей.
Загрузка процессора и памяти для каждой записи меньше, чем шары smurf, но для прохождения всех записей все равно требуется около 8 минут.В Ruby можно ли подключать базу данных по потокам?

Я бы хотел использовать потоки, но когда я дал это, у моего db закончились соединения. Конечно, это было, когда я попытался подключиться 200 раз, и действительно я мог бы ограничить это лучше, чем это. Но когда я нажимаю этот код до Героку (где у меня есть 20 связей для всех рабочих, чтобы поделиться), я не хотите случайно заблокировать другие процессы, потому что это ускорилось.

Я думал о рефакторинге кода, чтобы он соединил весь SQL, но это будет действительно очень грязно.

Так что мне интересно, есть ли трюк, позволяющий потокам обмениваться ссылками? Учитывая, что я не ожидаю, что переменная соединения изменится во время обработки, я действительно удивлен тем, что вилке потока необходимо создать новое соединение с БД.

Ну любая помощь будет супер круто (как и я) .. спасибо


SUPER надуманный Пример
Ниже 100% надуманный пример. Это показывает проблему.
Я использую ActiveRecord внутри очень простой темы. Кажется, каждый поток создает собственное подключение к базе данных. Я основываю это предположение на следующем предупреждающем сообщении.

START_TIME = Time.now 

require 'rubygems' 
require 'erb' 
require "active_record" 

@environment = 'development' 
@dbconfig = YAML.load(ERB.new(File.read('config/database.yml')).result) 
ActiveRecord::Base.establish_connection @dbconfig[@environment] 

class Product < ActiveRecord::Base; end 

ids = Product.pluck(:id) 
p "after pluck #{Time.now.to_f - START_TIME.to_f}" 

threads = []; 
ids.each do |id| 
    threads << Thread.new {Product.where(:id => id).update_all(:product_status_id => 99); } 
    if(threads.size > 4) 
    threads.each(&:join) 
    threads = [] 
    p "after thread join #{Time.now.to_f - START_TIME.to_f}" 
    end 
end 

p "#{Time.now.to_f - START_TIME.to_f}" 

ВЫВОД

"after pluck 0.6663269996643066" 
DEPRECATION WARNING: Database connections will not be closed automatically, please close your 
database connection at the end of the thread by calling `close` on your 
connection. For example: ActiveRecord::Base.connection.close 
. (called from mon_synchronize at /Users/davidrawk/.rvm/rubies/ruby-1.9.3-p448/lib/ruby/1.9.1/monitor.rb:211) 
..... 
"after thread join 5.7263710498809814" #THIS HAPPENS AFTER THE FIRST JOIN. 
..... 
"after thread join 10.743254899978638" #THIS HAPPENS AFTER THE SECOND JOIN 
+0

«Я думал о рефакторинге кода» - я подозреваю, что вам действительно понадобится - 80 000 запросов БД, как вы подразумеваете, будут медленными, что бы вы ни делали. Можете ли вы показать код? –

+0

Если вы используете ActiveRecord, то он уже доступен. – pguardiario

+0

Медленно все о перспективах. :) 80 000 за 8 минут было бы хорошо, если бы я не строил систему, чтобы обрабатывать пару миллионов. К сожалению, в коде нет ничего особенного. Просто небольшой скрипт для подключения и обновления записей. – baash05

ответ

2

Смотрите этот драгоценный камень https://github.com/mperham/connection_pool и ответ, пул соединений может быть то, что вам нужно: Why not use shared ActiveRecord connections for Rspec + Selenium?

Другим вариантом было бы использовать https://github.com/eventmachine/eventmachine и запускать задачи в EM .defer таким образом, что доступ БД происходит в блоке обратного вызова (внутри реактора) неблокирующим способом

Alternativ Ely, и более надежное решение тоже идти на облегченной фоне очереди обработки, таких как beanstalkd см https://www.ruby-toolbox.com/categories/Background_Jobs больше вариантов - это будет моя основная рекомендация

EDIT,

также, вы, вероятно, не» t имеет 200 ядер, поэтому создание 200 + параллельных потоков и соединений db не ускоряет процесс (фактически замедляет его), посмотрите, можете ли вы найти способ разделить проблему на несколько наборов, равных вашему числу corees + 1 и решить проблему таким образом,

это, вероятно, самое простое решение вашей проблемы

+0

Спасибо за ссылку пула соединений, это может быть билет.Мое приложение с 300-кратным рубином уже работает в Delayed_Job, который вроде почему я что-то искал. Это отстой, чтобы иметь 250megs барана и использовать 3megs, но в то же время есть 10 минут, чтобы выполнить работу, и взять 8 (или больше). Я хочу торговать скоростью для ram, а потоки «core +1», по-видимому, являются одним из способов добиться этого. У меня не было даже двух потоков перед вашим ответом, потому что соединения были моим пределом. Еще раз спасибо! – baash05

+0

Я передал вторую ссылку, и мое маленькое приложение разбилось каждый раз, когда пыталось подключиться в потоке. – baash05

+0

Событие машины запускает различные соединения с БД. :( – baash05

Смежные вопросы