ruby multithread,共享数组

时间:2016-02-11 14:16:27

标签: ruby multithreading

我有以下代码,其中@targets是主机名和ips的哈希,例如:

@targets = {
  "www.test.com"  => 1.2.3.4,
  "www.test2.com" => 4.3.2.1,
  "www.test2.com" => 23.24.25.23
}

代码有三个不同的“块”(块1,2,3)。 目前,每个线程都在一个主机/ IP对上工作。 我想创建三个线程,每个块一个。 因此,当block1在@targets["www.test.com"]写入时,block2会等待。 当block1完成时,block2在@targets["www.test.com"]写入,但block1不等待。相反,它开始在@targets["www.test2.com"]写作。

这就像互斥锁一样,但是当我使用互斥锁时,我不能/不知道怎么告诉block1“抓住下一个目标”

require 'thread'

@targets = {
  "www.test.com"  => "1.2.3.4",
  "www.test1.com" => "4.3.2.1",
  "www.test2.com" => "23.24.25.23"
}

@vhosts={
"www.test.com"=>"web.test.com",
"www.test1.com"=>"Error",
"www.test2.com"=>"dev.test2.com"
}

@enumeration_summary={}

@targets.each do |host,ip|

  @initialize = Thread.new do

    #---------block1---------
    puts "Host: #{host} Ip: #{ip}"
    @enumeration_summary["#{host}"]={}
    #---------block1 end---------

    #---------block2---------
    @enumeration_summary["#{host}"]={ip: ip}
    #---------block2 end---------

    #---------block3---------
    if /Error/ === @vhosts["#{host}"]
       @enumeration_summary["#{host}"][:vhosts_number_of_results]=@vhosts["#{host}"]
    else
       @enumeration_summary["#{host}"][:vhosts_number_of_results]=@vhosts["#{host}"].size
    end
    #---------block3 end---------

  end #end thread

end #end of targets.each

 @initialize.join

puts "===> #{@enumeration_summary}"

有时候我没有得到所有的结果,我不明白为什么。 此时,每个线程都访问@enumeration_summary哈希的不同索引。那么为什么我不能一直得到所有的结果呢? 示例输出: 示例1.一切正常:

Host: www.test.com Ip: 1.2.3.4
Host: www.test2.com Ip: 23.24.25.23Host: www.test1.com Ip: 4.3.2.1

===> {"www.test.com"=>{:ip=>"1.2.3.4", :vhosts_number_of_results=>12},  "www.test1.com"=>{:ip=>"4.3.2.1", :vhosts_number_of_results=>"Error"}, "www.test2.com"=>{:ip=>"23.24.25.23", :vhosts_number_of_results=>13}}

示例2.目标test1.com缺失

Host: www.test.com Ip: 1.2.3.4
Host: www.test2.com Ip: 23.24.25.23
Host: www.test1.com Ip: 4.3.2.1
===> {"www.test.com"=>{:ip=>"1.2.3.4", :vhosts_number_of_results=>12}, "www.test2.com"=>{:ip=>"23.24.25.23", :vhosts_number_of_results=>13}}

P.S:我只想与“线程”合作。我想避免使用任何其他gem,例如“parallel”。

提前致谢。

2 个答案:

答案 0 :(得分:0)

这未经过测试,但它依赖于Queue文档中的示例。它将消息从block1传递到block2,从block2传递到block3,每个消息在到达时处理:

require 'thread'

queue = Queue.new
queue2 = Queue.new

producer = Thread.new do
  @targets.each do |host,ip|
    puts "Host: #{host} Ip: #{ip}"
    @enumeration_summary["#{host}"]={}
    queue << [host, ip, @enumeration_summary["#{host}"]]
  end
  queue = nil
end

consumer1 = Thread.new do
  while value = queue.pop
    value[2] = { ip: value[1] }
    queue2 << value
  end
  queue2 << nil
end

consumer2 = Thread.new do
  while value = queue2.pop
    if /Error/ === @vhosts[value[0]]
      value[2][:vhosts_number_of_results]=@vhosts[value[0]]
    else
      value[2][:vhosts_number_of_results]=@vhosts[value[0]].size
    end
  end
end

consumer2.join

答案 1 :(得分:0)

创建线程时,将每个线程分配给@initialize :(覆盖变量的先前值)

@targets.each do |host, ip|
  @initialize = Thread.new do
    # ...
  end
end
@initialize.join

最后一行只等待分配给@initialize的线程,即最后一个线程。

为了等待所有线程,你必须将它们分配给一个数组,例如:

@threads = []
@targets.each do |host, ip|
  @threads << Thread.new do
    # ...
  end
end
@threads.each(&:join)