Рубиновые темы - не хватает ресурсов - PullRequest
0 голосов
/ 28 февраля 2011

Я написал следующий сканер, чтобы взять список URL-адресов из файла и извлечь страницы.Проблема в том, что примерно через 2 часа система становится очень медленной и почти неработоспособной.Система является четырехъядерным Linux с оперативной памятью 8 ГБ.Может кто-нибудь сказать мне, как решить эту проблему.

require 'rubygems'
require 'net/http'
require 'uri'

threads = []
to_get = File.readlines(ARGV[0])

dir = ARGV[1]
errorFile = ARGV[2]

error_f = File.open(errorFile, "w")

puts "Need to get #{to_get.length} queries ..!!"
start_time = Time.now

100.times do
  threads << Thread.new do
    while q_word = to_get.pop
      toks = q_word.chop.split("\t")

      entity = toks[0]
      urls = toks[1].chop.split("::")
      count = 1

      urls.each do |url|
        q_final = URI.escape(url)
        q_parsed = URI.parse(q_final)

        filename = dir+"/"+entity+"_"+count.to_s

        if(File.exists? filename)
          count = count + 1
        else
          begin
            res_http = Net::HTTP.get(q_parsed.host, q_parsed.request_uri)
            File.open(filename, 'w') {|f| f.write(res_http) }
          rescue Timeout::Error
            error_f.write("timeout error " + url+"\n")
          rescue 
            error_f.write($!.inspect + " " + filename + " " + url+"\n")
          end
          count = count + 1
        end
      end
    end
  end 
end

puts "waiting here"

threads.each { |x| x.join }
puts "finished in #{Time.now - start_time}"
#puts "#{dup} duplicates found"
puts "writing output ..."
error_f.close()
puts "Done."

Ответы [ 5 ]

3 голосов
/ 01 марта 2011

Как правило, вы не можете изменять объекты, общие для потоков, если только эти объекты не потокобезопасны .Я бы заменил to_get на экземпляр Queue, который является поточно-ориентированным.

Перед созданием любых потоков:

to_get = Queue.new
File.readlines(ARGV[0]).each do |url|
  to_get.push url.chomp
end
number_of_threads.times do
  to_get.push :done
end

И в потоке:

loop do
  url = to_get.pop
  break if url == :done
  ...
end
1 голос
/ 01 марта 2011

Для проблем такого типа я настоятельно рекомендую вам взглянуть на EventMachine .Проверьте этот пример того, как получать URL-адреса параллельно с EventMachine и Ruby.

0 голосов
/ 01 марта 2011

Когда у меня есть куча URL для обработки, я использую Typhoeus и Hydra .Hydra позволяет легко обрабатывать несколько запросов одновременно.Проверьте times.rb пример для начальной точки.

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

Я бы также рекомендовал использовать базу данных для отслеживания очереди файлов.Вы нажимаете на другой сервер, чтобы получить эти файлы, и вам нужно начинать с начала прогона и снова получать те же файлы, что является большой тратой времени и ресурсов для вас и любого, кто их обслуживает.В начале работы запустите базу данных и найдите все файлы, которые не были извлечены, возьмите их и установите их флаг «загружен».Если вы запускаете и все файлы были загружены, вы знаете, что предыдущий запуск был успешным, поэтому очистите их все и запустите с самого начала списка.Вам нужно будет потратить некоторое время, чтобы выяснить, что должно быть в такой базе данных, но, если ваши потребности возрастут, ваше время выполнения увеличится, и вы столкнетесь со временем, которое вы выполняли большую часть дня, иотключение питания или сбой системы.Вы не хотите начинать с самого начала в этой точке.Скорость использования базы данных не снижается по сравнению с медленной передачей файлов через Интернет.

0 голосов
/ 01 марта 2011

Я не очень разбираюсь в управлении памятью или в поиске того, что потребляет слишком много памяти в Ruby (хотелось бы знать больше), но в настоящее время у вас работает 100 потоков одновременно.Может быть, у вас должно быть только 4 или 8 работающих одновременно?

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

0 голосов
/ 28 февраля 2011

Проблема, наверное, с оперативной памятью.Все загруженные файлы сохраняются в памяти после загрузки и сохранения их.(Я не знаю, большие ли это файлы, сколько вы можете скачать через 2 часа через Интернет?) Попробуйте очистить память с помощью GC.start.Что-то вроде добавления этого в начале файла:

Thread.new do
  while true
    sleep(60*5) # 5 minutes
    GC.start
  end
end

Обратите внимание, что GC.start остановит все остальные запущенные потоки во время работы.Если загрузка прервалась, уделите меньше времени (будет меньше вещей для очистки).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...