Rails threading - несколько задач

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

Я поигрался, попробовал allow_concurrency, для которого я установил значение true, или config.thread_safe! но я получаю недетерминированные ошибки, например, иногда отсутствует класс или константа ...

вот код

grabbers = get_grabber_name_list
threads = []
grabbers.each { |grabber|
  threads << Thread.new {
    ARGV[0] = grabber
    if (@@last_run_timestamp[grabber.to_sym].blank? || (@@last_run_timestamp[grabber.to_sym] >= AbstractGrabber.aff_net_accounts(grabber, "grab_interval").seconds.ago))
    Rake::Task["aff_net:import:" + grabber].execute
    @@last_run_timestamp.merge!({grabber.to_sym => Time.now})
  end
  }
}
threads.each {|t| t.join }

Благодарность


person Community    schedule 04.11.2009    source источник


Ответы (2)


Недавно я реализовал приложение Rails, использующее потоки, и сделал несколько открытий:

Во-первых, если вы пишете в какие-либо массивы или хэши (например, сложные типы) вне вашего потока, заключите их в мьютекс. Мне кажется, что ссылки на хэш и массивы не могут быть потокобезопасными. Кажется маловероятным, что индексация элементов хэша / массива не является потокобезопасной, но все, что я знаю, это то, что после того, как я поместил внешние структуры данных в мьютекс перед записью, проблемы исчезли.

Во-вторых, закройте соединение ActiveRecord, когда поток завершится, иначе вы можете создать большое количество устаревших соединений. Вот сообщение о том, как это сделать. >. Я не знаю, применимо ли это по-прежнему к версиям Rails> 2.2, но после того, как я начал явно закрывать соединения, мои проблемы исчезли. Автор предлагает исправить ActiveRecord, чтобы сделать это автоматически, но я решил явно освободить соединения в своем коде.

Вот пример кода, который у меня работает:

mutex = Mutex.new
my_array = []
threads = []
1.upto(10) do |i|
  threads << Thread.new {
     begin
       do_some_stuff
       mutex.synchronize {
         # You'd think that each thread would only touch its own personal
         # array element but without a mutex, I run into problems.
         my_array[i] = some_computed_value
       }
     ensure
       ActiveRecord::Base.connection_pool.release_connection
     end
   }
}
threads.each {|t| t.join}

Кстати, если вы используете потоки для использования преимуществ многоядерных процессоров, вам необходимо использовать JRuby. Насколько мне известно, JRuby - единственная реализация, которая может использовать собственные потоки ЦП. Если вы используете потоки, чтобы делать другие вещи во время ожидания сетевых подключений или некоторых других задач, не связанных с процессором, это не проблема.

person Mark Westling    schedule 04.11.2009

Вероятно, вам следует сделать это с помощью фоновых воркеров. Есть несколько вариантов для библиотек фоновых рабочих, но мой любимый - это delayed_job (http://github.com/tobi/delayed_job).

Должно быть довольно легко преобразовать опубликованный вами код в фоновые задания.

person jonnii    schedule 04.11.2009