1

我想做一个每秒调用远程服务的功能。为此,我有这样的事情:

stop = false
text = ""

while stop == false
  r = RestClient.post 'http://example.com'
  text += r.to_str
  sleep 1
  # after a treatment, the value of stop will set to true
end

问题是程序被阻塞,直到 http 请求完成并且我不想要它。我可以将此代码放在子进程中,但我想将结果保持在调用顺序中。例如,我可以有这个请求:

 time | anwser
--------------
  10  | Happy
  100 | New
  10  | Year

第二个请求比第三个请求长,因此,对于线程,我将在第二个之前得到第三个结果,变量的值text将是HappyYearNewand I want HappyNewYear

我有办法拥有多个流程并保持原始订单吗?这是一个很小的程序,如果可能的话,我不想安装像redis这样的服务器。

4

2 回答 2

1

使用哈希

从 ruby​​-1.9 开始,哈希键顺序得到保证。一个简单的解决方案是利用这一点,将您的请求放入哈希中并存储其结果,通过其 key 访问哈希元素:

requests = {
  foo: [ 'a', 1 ],
  bar: [ 'b', 5 ],
  foobar: [ 'c', 2 ]
}

requests.each do |name, config|
  Thread.new( name, config ) do |name, config|
    sleep config[1]
    requests[ name ] = config[0]
  end
end

sleep 6

requests.each do |name, result|
  puts "#{name} : #{result}"
end

生产:

foo : a
bar : b
foobar : c

因此,要匹配您提供的代码:

stop, i, text, requests = false, 0, '', {}

until stop
  i += 1
  requests[ i ] = nil

  Thread.new( i ) do |key|
    r = RestClient.post 'http://example.com'
    requests[ i ] = r.to_str
    sleep 1
    # after a treatment, the value of stop will set to true
  end
end

# you will have to join threads, here
text = requests.values.join

使用数组

如果最后一个示例对您有好处,您甚至可以使用数组来简化它。数组顺序当然也得到保证,您可以利用 ruby​​ 数组动态大小特性:

a = []
a[5] = 1
p a
=> [nil, nil, nil, nil, nil, 1]

所以,前面的例子可以重写:

stop, i, text, requests = false, 0, '', []

until stop
  i += 1

  Thread.new( i ) do |key|
    r = RestClient.post 'http://example.com'
    requests[ i ] = r.to_str
    sleep 1
    # after a treatment, the value of stop will set to true
  end
end

# you will have to join threads, here
text = requests.join
于 2013-11-06T18:51:39.003 回答
0

这是一个非常简单的线程解决方案。我将结果和 rmutex 作为实例变量,您可以将它们设为全局、类或许多其他内容:

stop = false
Thread.current[:results] = {}
Thread.current[:rmutex] = Mutex.new
counter = 0

while(!stop)
  Thread.new(counter, Thread.current) do |idex, parent|
    r = RestClient.post 'http://example.com'
    parent[:rmutex].lock
    parent[:results][idex] = r.to_str
    parent[:rmutex].unlock
  end
  sleep 1
end

text = Thread.current[:results].to_a.sort_by {|o| o[0]}.map {|o| o[1]}.join

这通过将“索引”存储到每个线程操作所在的获取中,将结果与其索引一起存储,并在最后按索引排序后将它们放在一起。

于 2013-11-06T18:30:20.490 回答