Ruby создает только 3 потока одновременно - PullRequest
6 голосов
/ 14 февраля 2009

Я пытаюсь запустить 500 клиентов, которые одновременно отправляют некоторый запрос на сервер для целей нагрузочного тестирования. Клиент снова является программой ruby. Звучит банально. Но я столкнулся со странной проблемой с рубиновыми нитями. Мой код выглядит так -

n = 10

n.times do
  Thread.new do
    `calc`
  end
end

Код является примером. Я просто пытаюсь запустить команду calc из командной строки (если вы пробуете этот код на платформе, отличной от Windows, замените ее на какую-нибудь команду, которая работает в вашей командной строке или оболочке). Позже это будет заменено на 'ruby my_client.rb', а также значение n будет установлено на 500 (или что-то еще).

Проблема, с которой я здесь сталкиваюсь, заключается в том, что независимо от количества потоков, которые я хочу создать, одновременно создаются только 3 потоков. То есть только 3 окна калькулятора открываются одновременно. Остальные потоки просто ждут в очереди, ожидая завершения этих 3 потоков. Может быть, это как-то связано с блокирующими и неблокирующими вызовами. Но я попробовал Java-эквивалент той же программы, и он работал отлично. Это старая поговорка, что нити в ruby ​​не рекомендуются. Правда ли, что это проблема с нитями Руби или я что-то не так делаю?

Ответы [ 4 ]

4 голосов
/ 14 февраля 2009

Проблема, которую вы наблюдаете, специфична для приложений с графическим интерфейсом. Становится намного лучше, когда вы запускаете командную строку внутри рабочих.

С приведенным ниже примером я могу нормально запустить 200 экземпляров wget, что, вероятно, достаточно для целей нагрузочного тестирования.

n = 200

threads = []
(1..n).each do |i|
  threads << Thread.new do
    puts `wget google.com` # forgive me google
    sleep 10
    puts "#{i} done"
  end
end

threads.each do |t| # wait until all workers are done
  t.join
end

Вероятно, вы могли бы получить гораздо больше рабочих, если бы переключились с wget на код Ruby для загрузки веб-страниц. И все же, вы должны помнить, что потоки Ruby масштабируются только так далеко. Не ожидайте, что многие тысячи или параллельные потоки будут работать нормально - попробуйте вместо этого подпроцессы или подход на основе продолжения.

3 голосов
/ 14 февраля 2009

Реализация Ruby (MRI) для "Matz" C не использует собственные потоки до версии 1.8.6. Я полагаю, что это изменилось в Ruby 1.9, но я понимаю, что мы, вероятно, все еще не увидим большой многопоточной производительности из-за Глобальной блокировки интерпретатора.

Если вам действительно нужна хорошая многопоточная поддержка, и если ваше программное обеспечение написано на Ruby, вы можете попробовать запустить его на JRuby. Быстрая проверка работоспособности показала, что по вашему примеру я получу 2 потока ОС на MRI и 12 при запуске той же вещи под JRuby. Это было на OS X с использованием "MRI" 1.8.6 и JRuby 1.1.6.

Другой вариант, поскольку похоже, что вы порождаете поток, чтобы форкнуть новый процесс, может вместо этого использовать DRb.

0 голосов
/ 14 февраля 2009

Возможно, вы захотите порождать отдельные процессы. Kernel::fork не работает под Windows, поэтому вам придется использовать старые добрые Kernel::system или Kernel::popen и создавать для них отдельные сценарии или использовать специальные аргументы командной строки.

Несмотря на то, что Ruby 1.9 почти готов, и если вы можете включить его, у него есть собственные потоки ОС, и ничего подобного не произойдет.

0 голосов
/ 14 февраля 2009

Это отлично сработало для меня на OS X с TextMate.

n = 10

threads = []
n.times do |i|
  threads << Thread.new do
    `mate test#{i}.txt`
  end
end

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