Ruby一次只会创建3个线程

6

我正在尝试同时运行500个客户端向服务器发送请求,以进行负载测试。客户端是一个Ruby程序。听起来很简单。但是我在处理Ruby线程时遇到了奇怪的问题。我的代码如下 -

n = 10

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

这段代码是一个示例。我只是尝试从命令行运行calc命令(如果您正在其他平台上尝试此代码,请将其替换为在您的命令行或shell上有效的某个命令)。这将稍后被'ruby my_client.rb'所取代,同时n的值将被设置为500(或其他值)。

我面临的问题是,无论我想要创建多少个线程,一次只会创建3个线程。也就是说,只有3个calc窗口同时打开。其余的线程只是在队列中等待这3个线程终止。可能与阻塞和非阻塞调用有关。但是我尝试了相同程序的Java版本,它完美地工作了。有人说Ruby中的线程并不推荐使用。这是真的吗?这是Ruby线程的问题还是我做错了什么?


在Debian GNU/Linux上,1.8.7.72-2很好用。我认为可能是由于某些Windows特定的原因导致的。 - womble
这是可能的,但是Java程序在同一平台、同一台机器上运行得非常完美。 - Chirantan
在 Windows XP SP3 下使用 Ruby 1.8.7 对我来说运行良好。 - Lolindrath
4个回答

4
你观察到的问题是特定于GUI应用程序的。当你在工作进程中运行命令行时,情况会好得多。
使用下面的示例,我可以轻松运行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线程只能扩展到一定程度。不要期望成千上万个并行线程能够正常工作,可以尝试使用子进程或基于continuation的方法。


我在 Windows XP SP3,ruby 1.8.7 下运行了这段代码,完全没有问题。 - Lolindrath

3
"Matz" C实现的Ruby(MRI)在1.8.6之前没有使用本地线程。我相信这在Ruby 1.9中已经改变了,但由于全局解释器锁定,我们可能仍然无法看到良好的多线程性能。
如果您确实需要良好的多线程支持,并且希望使用Ruby编写软件,则可以尝试在JRuby上运行它。一个快速的测试表明,在OS X上使用“MRI”1.8.6和JRuby 1.1.6时,使用您的示例将获得2个OS线程和12个线程。
另一个选择是,既然看起来您正在生成一个线程以便分叉一个新进程,那么可能要改用DRb。"

感谢提供 DRb 的指引。Jruby 应该可以解决这个问题。虽然我没有 DRb 的经验,但我会学习并尝试一下。谢谢 :) - Chirantan
虽然 Ruby 只有绿色线程,但这并不意味着它只能同时运行三个线程。 - womble
那确实看起来像是一个原因。 - vava
Ruby 有一个非常大的 IO 锁,对我来说使得线程几乎没用。 :/ - reto

0
你可能希望使用单独的进程。`Kernel::fork`在Windows下不起作用,因此您必须使用老式的`Kernel::system`或`Kernel::popen`并创建单独的脚本,或者使用特殊的命令行参数。
虽然Ruby 1.9已经接近目标了,如果您可以切换到它,它确实具有本地操作系统线程,这样的事情就不会发生。

0

这个在我的 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 }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接