0

我正在尝试从网站上抓取一些信息,但我以前从未使用过线程。我将这个测试组合在一起以模仿我正在尝试做的事情:

require 'thread'
mutex = Mutex.new
mut = Mutex.new
hash = {}
n = 0
a = []
b = []
# x = 0
10.times do |i|
 a << Thread.new(i) do |top_index|
   mutex.synchronize do
     hash[top_index] = []
     sleep 0.2
     100.times do |sub_index|
       b << Thread.new(top_index, sub_index, hash) do |t, s, my_hash|
         mut.synchronize do
           r = s
           sleep 0.2
           my_hash[t].push(s)
         end
       end
     end
     b.each {|y| y.join }
     puts "sub: #{top_index} - #{hash[top_index].length}"
     puts hash[top_index]
   end
 end
end
a.each {|q| q.join }
hash.each { |key, value| n += value.length }
puts "Final Tally - #{n}"

sleep代表一些 RestClient请求,以及代表我从网站上抓取的一些信息的排序和 ing的get数字。push但是当查看输入所有内容的顺序时,我注意到数组之间的模式,所以我想知道何时r在一个线程中分配它会影响它在另一个线程中的值。但这没有意义,因为这将严重限制它对并发请求的有用性。

另外,我认为由于一切都是并发的(或表现得像并发的),它应该在几秒钟内与睡眠定时器一起返回,但实际上需要相当长的一段时间。

我刚刚测试了它,它实际上比没有线程花费更长的时间?

线程总时间:204.04028

正常总数:203.133638

所以,现在我很困惑。

4

1 回答 1

1

我不知道您注意到什么“模式”;但一般来说,您Thread在示例中使用初始化程序的方式应该按您的预期工作。

我刚刚测试了它,它实际上比没有线程花费更长的时间?

这是因为您正在同步使用这些线程所做的所有工作。所以并发性为零。因此,单线程解决方案优于“多线程”解决方案是有道理的,因为后者只是做与前者相同的工作(以相同的顺序),但产生线程的额外开销(并使它们等待)。

您不需要同步这些操作。Ruby 解释器有一个全局解释器锁,它可以防止开发人员在低级语言中遇到的大多数竞争条件。您希望使用 a 的主要场景是当 Ruby 领域之外Mutex可能发生需要同步的事情(例如,一些较低级别的系统操作)时。

这是您的示例的精简版本(没有同步),效果很好:

require 'thread'

hash = {}
outer_threads = []
inner_threads = []

10.times do |i|
 outer_threads << Thread.new(i) do |top_index|
   hash[top_index] = []
   sleep 0.2
   20.times do |sub_index|
     inner_threads << Thread.new(top_index, sub_index, hash[top_index]) do |t, s, arr|
       sleep 0.2
       arr.push(s + 1)
     end
   end
   inner_threads.each(&:join)
 end
end

outer_threads.each(&:join)

# Verify that the hash is populated with arrays comprising the numbers 1 to 20,
# as we would expect.
hash.each do |key, value|
  puts "#{key}: #{value.sort.join(', ')}"
end
于 2013-10-09T23:04:00.803 回答