2

我正在编写一个脚本来 ping 我的 ip 范围。这是我到目前为止所拥有的:

lines = `ipconfig`.split("\n")
thr = []
ip_line = lines.detect { |l| l=~/Ip Address/i }
matcher = /\d+\.\d+\.\d+\.\d+/.match(ip_line)
if matcher.length > 0
    address = matcher[0]
    address.sub!(/\.\d+$/,"")
    (1 .. 254).each do |i|
        xaddr = address + "." + i.to_s
        puts "pinging #{xaddr}"
        thr << Thread.new {
            `ping #{xaddr}` 
        }
    end

    thr.each do |t|
        t.join
        output = t.value
        puts output
    end
end

问题是,这执行得非常慢。就像应用程序没有线程一样。这是为什么?我注意到,如果我将 Thread 子类化,整个事情的运行速度会快得多。怎么了?Thread 不是用于直接使用吗?

4

3 回答 3

6

Ruby 线程由 Ruby 解释器控制。对于操作系统,Ruby Interpreter 仍然只是一个进程(就像任何其他进程一样)。Ruby Interpreter 将一个进程拆分为多个 ruby​​ 线程。

`ping #{xaddr}`  

此行强制 Ruby 解释器暂时放弃其控制权,因为您要求操作系统执行另一个进程。直到“ping”完成后,ruby 解释器才会重新获得控制权。这可能是代码慢的原因。

于 2009-09-05T17:36:52.400 回答
3

你可以像这样使用IO.popen

thr << Thread.new xaddr do |adr|
  IO.popen "ping #{adr}" do |io|
    io.each {|l| puts l}
  end
end

这样,即使使用绿色线程,您也可以获得更多的并发性。原因是解释器不必等到发送完 ping 的完整输出。

于 2009-09-07T14:23:31.773 回答
1

您正在运行什么 Ruby 实现?在标准 Ruby 中,线程是“绿色线程”,即不是真正的操作系统线程,而是由 Ruby 运行时提供的。

在 JRuby 中,线程是真正的 OS 线程,因为这就是 JVM 实现它们的方式。

因此,您可能会看到不同 Ruby 实现之间的线程性能差异。请注意,尽管 Ruby 1.9 比 JRuby 更快(至少在某些基准测试中),但 JRuby 被认为比 Ruby 1.8.6 更快。

于 2009-09-05T14:46:05.997 回答