LINUX.ORG.RU

Куда копать для распараллеливания задачи в ruby?

 


0

2

Пусть в текстовом файле 1000 строк с ip-адресами, и необходимо выполнить на каждый адрес telnet-сессию + какие-либо действия на самом узле. Сейчас алгоритм такой: считать текстовый файл в массив -> для каждого полученного элемента этого массива поочередно выполнять host=Net::Telnet::new ... Возможно ли выполнять вышеописанное не для одного узла за раз, а, например, для десяти?

юзай Thread, это стандартная библиотека, они как-раз хороши для IO bound задач

anonymous ()

такая хрень делается шелом..спроси админа - он расскажет как.

MKuznetsov ★★★★★ ()

Смотри примеры с тредами из любого букваря. Настоящей параллельности не будет, ибо GIL, но пока один тред ждет IO руби может выполнять другой. Или просто юзай форк, если не нужно никакого взаимодействия.

anonymous ()
Ответ на: комментарий от anonymous

Между собой взаимодействия не нужно, спасибо за наводку.

hasculdr ()
Ответ на: комментарий от anonymous

Я хэлоувордщик, функционал требуется наколеночный, кроме азов ruby не знаком ни с чем вообще, даже с башем. Была опробована такая конструкция:

buffer=File.open("путь к файлу").readlines
thr=Thread.new { buffer.each {|ip|
	begin
	host=Net::Telnet::new("Host" => ip, "Timeout" => 5, "Waittime" => 2, "Prompt" => /[#>\]-]/)
        ver=host.cmd("<требуемое действие>")
	host.close
	puts ver
	rescue Net::ReadTimeout #в случае ошибки продолжаем обход массива
  $stderr.puts #сообщение об ошибке
end
				} #конец блока buffer.each
} #конец потока thread
thr.join
puts thr #здесь мне выдается 16-ричное значение, а я ожидал перечисления результатов выполнения каждого процесса
Вышеописанное выполняется как и ранее, последовательно. В чем мой алгоритм ошибочен?

hasculdr ()
Ответ на: комментарий от hasculdr

Асинхронные сокеты, конечно! и FSM. С тредами тоже можно, возможно даже удобнее будет, но не обязательно.

yoghurt ★★★★★ ()
Ответ на: комментарий от hasculdr

ошибка в том, что ты запускаешь 1 тред и в нём устраиваешь цикл.

Тебе надо в цикле запустить N тредов и дождаться окончания всех

yoghurt ★★★★★ ()
Ответ на: комментарий от yoghurt

Т.е. «вручную» разбить массив из тысячи элементов на сто массивов по десять элементов, и «вручную» запустить сто потоков? Как теоретически такое сделать для заранее неизвестного/периодически изменяющегося количества элементов в исходном массиве?

hasculdr ()
Ответ на: комментарий от hasculdr

Сто потоков - это это из области бреда, руби это такое тормозное гавно, что 100 потоков - верная смерть. Задачу можно решить так: создаешь пул потоков (небольшой, например равный числу ядер-2); создаешь очередь задач, в которую основной поток пихает задания, а другой поток их достает и кладет на свободный поток из пула, или ждет пока кто-то освободится. Классика жанра.

Bobby_ ()
Ответ на: комментарий от hasculdr

Возьми гем parallel

buffer=File.open("путь к файлу").readlines
results = Parallel.map(buffer, in_threads: <кол-во желаемых нитей>) do |ip|
            # Telnet и прочая фигня
          end

dr_jumba ()
Ответ на: комментарий от hasculdr

разбивать вместо ста на N, но выше тебе уже подсказали более верное решение с пулами и очередями

yoghurt ★★★★★ ()
Ответ на: комментарий от Bobby_

Сто потоков - это это из области бреда, руби это такое тормозное гавно, что 100 потоков - верная смерть.

Тормозить будет ось, а не руби. В данном случае кода исчезающе мало, все упрется в IO. Так что нужны неблокирующие операции, только и всего. Неужели в руби этого нет из коробки? Даже в тикле было испокон веков.

anonymous ()

Ребят, прошу прощения за такую наглость, но реально вынужден обратиться на каналы к вам, братьям-программистам, потому что у меня жопа по жизни и мне не у кого больше попросить помощи. Подробнее у меня на форуме:

https://russiancoders.tech/topic/7lTc4SC5HWjNXyZjqfMh/18/#177

anonymous ()
Ответ на: комментарий от hasculdr

google://ruby thread-safe queue
представь, у тебя есть массив (Array) из каких-то элементов, в твоём случае айпишников. и нужное кол-во тредов просто просят (pop) у этого массива последний\первый элемент. это называется очередь.
но не простая, а thread-safe, значит, что треды не смогут случайно получить один и тот-же элемент.
треды просто работают и забирают из очереди по одному элементу, тебе пофигу на длину очереди, если элементы в ней не протухают со временем. так что, не надо ничего делить на сто.

system-root ★★★★★ ()
Последнее исправление: system-root (всего исправлений: 1)
Ответ на: комментарий от hasculdr

Тебе верно сказали - вызов потоков нужно делать внутри цикла:

  lines = File.open("путь к файлу").readlines
  lines.each do |ip|
    Thread.new do
      begin
        host = Net::Telnet::new("Host" => ip, "Timeout" => 5, \
          "Waittime" => 2, "Prompt" => /[#>\]-]/)
        ver = host.cmd("<требуемое действие>")
        puts ver
        host.close
      rescue => err
        $stderr.puts('Exception: '+err.message)
      end
    end
  end

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

Novator ★★★★★ ()
Последнее исправление: Novator (всего исправлений: 3)
Ответ на: комментарий от anonymous

Тогда пусть делает тупую задержку (sleep 1) или умную приостановку, пока N хостов в работе:

  N = 10
  $num = 0
  lines = File.open("путь к файлу").readlines
  lines.each do |ip|
    while $num >= N do
      sleep(0.2)
    end
    Thread.new do
      $num += 1
      begin
        host = Net::Telnet::new("Host" => ip, "Timeout" => 5, \
          "Waittime" => 2, "Prompt" => /[#>\]-]/)
        ver = host.cmd("<требуемое действие>")
        puts ver
        host.close
      rescue => err
        $stderr.puts('Exception: '+err.message)
      end
      $num -= 1
    end
  end
Novator ★★★★★ ()
Последнее исправление: Novator (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.