我正在尝试运行500个客户端,这些客户端同时向服务器发送一些请求以进行负载测试。客户端再次成为ruby程序。听起来微不足道。但是我遇到了ruby线程的奇怪问题。我的代码看起来像这样 -
n = 10
n.times do
Thread.new do
`calc`
end
end
代码是一个示例。我只是试图从命令行运行calc
命令(如果您在Windows以外的平台上尝试此代码,请将其替换为适用于您的命令行或shell的命令)。稍后将替换为“ruby my_client.rb
”,并且n的值将设置为500(或其他)。
我在这里遇到的问题是,无论我想创建多少个线程,一次只能创建 3 个线程。那只是同时打开3个计算窗口。剩余的线程只是在队列中等待等待这3个线程的终止。可能与阻止和非阻塞调用有关。但是我尝试了Java相同的程序,它运行得很好。这是一句老话,不建议使用红宝石线。这是Ruby的线程存在问题还是我做错了?
答案 0 :(得分:4)
您正在观察的问题特定于GUI应用程序。当你在worker中运行命令行时,它会变得更好。
通过下面的示例,我可以很好地运行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线程只能扩展到那么远。不要指望有数千个或并行线程可以正常工作 - 尝试使用子进程或基于延续的方法。
答案 1 :(得分:3)
Ruby(MRI)的“Matz”C实现不使用1.8.6的本机线程。我相信这在Ruby 1.9中有所改变,但据我所知,由于Global Interpreter Lock,我们可能仍然不会看到出色的多线程性能。
如果您确实需要良好的多线程支持,并且您的软件可以用Ruby编写,那么您可以尝试在JRuby上运行它。一个快速的健全性测试表明,使用你的例子我将在MRI上获得2个OS线程,在JRuby下运行相同的东西时获得12个。这是在OS X上使用“MRI”1.8.6和JRuby 1.1.6。
另一种选择,因为看起来你要生成一个线程来分叉一个新进程,可能会改为使用DRb。
答案 2 :(得分:0)
这对我来说非常适合我与osx一起使用。
n = 10
threads = []
n.times do |i|
threads << Thread.new do
`mate test#{i}.txt`
end
end
threads.each { |t| t.join }
答案 3 :(得分:0)
您可能希望生成单独的进程。 Kernel::fork
在Windows下不起作用,因此您必须使用旧的Kernel::system
或Kernel::popen
并为其创建单独的脚本或使用特殊的命令行参数。
虽然Ruby 1.9几乎就在那里,如果你可以打开它,它确实有本机操作系统线程,那样的东西就不会发生。