Как обрабатывать элементы в массиве параллельно, используя Ruby (и open-uri)

Мне интересно, как я могу открыть несколько одновременных подключений с помощью open-uri? Я ДУМАЮ, что мне нужно как-то использовать потоки или волокна, но я не уверен.

Пример кода:

def get_doc(url)
  begin
    Nokogiri::HTML(open(url).read)
  rescue Exception => ex
    puts "Failed at #{Time.now}"
    puts "Error: #{ex}"
  end
end

array_of_urls_to_process = [......]

# How can I iterate over items in the array in parallel (instead of one at a time?)
array_of_urls_to_process.each do |url|
  x = get_doc(url)
  do_something(x)
end

person Mario Zigliotto    schedule 26.09.2011    source источник


Ответы (5)


Также есть гем под названием Parallel, который похож на Peach, но активно обновляется.

person x1a4    schedule 26.09.2011
comment
Этот драгоценный камень - наркотик AF. Если вам нужно получить индекс, обязательно используйте each_with_index вместо обратных вызовов start или finish. Это в 10-50 раз более производительно. - person Joshua Pinter; 19.11.2018

Я надеюсь, что это дает вам представление:

def do_something(url, secs)
    sleep secs #just to see a difference
    puts "Done with: #{url}"
end

threads = []
urls_ary = ['url1', 'url2', 'url3']

urls_ary.each_with_index do |url, i|
    threads << Thread.new{ do_something(url, i+1) }
    puts "Out of loop #{i+1}"
end
threads.each{|t| t.join}

Возможно, создав метод для Array, например:

class Array
    def thread_each(&block)
        inject([]){|threads,e| threads << Thread.new{yield(e)}}.each{|t| t.join}
    end
end

[1, 2, 3].thread_each do |i|
    sleep 4-i #so first one ends later
    puts "Done with #{i}"
end
person derp    schedule 26.09.2011
comment
этот поток безопасен? см. stackoverflow.com/questions/17765102/ - person kraftydevil; 10.11.2018

module MultithreadedEach
  def multithreaded_each
    each_with_object([]) do |item, threads|
      threads << Thread.new { yield item }
    end.each { |thread| thread.join }
    self
  end
end

Использование:

arr = [1,2,3]

arr.extend(MultithreadedEach)

arr.multithreaded_each do |n|
  puts n # Each block runs in it's own thread
end
person Cameron Martin    schedule 13.07.2014

Простой метод с использованием потоков:

threads = []

[1, 2, 3].each do |i|
  threads << Thread.new { puts i }
end

threads.each(&:join)
person Dorian    schedule 30.06.2017

Существует гем под названием peach (https://rubygems.org/gems/peach), который позволяет вам это:

require "peach"

array_of_urls_to_process.peach do |url|
  do_something(get_doc(url))
end
person Daniel Brockman    schedule 26.09.2011
comment
Драгоценный камень только jruby - person Mike Atlas; 03.03.2015