将许多请求线程发布到同一网址

时间:2017-01-13 06:44:07

标签: ruby multithreading parallel-processing faraday typhoeus

我构建了一个像这样的json块:

data = {
    "url" : "http://www.example.com/post",
    "postdata" : [
        { "key1" : "value1" },
        { "key2" : "value2" },
        { "key3" : "value3" },
        { "key4" : "value4" },
        { "key5" : "value5" },
        { "key6" : "value6" }
    ]
}

我试图将'postdata'中的每个块并行(比如一个2的池)发布到同一个'url'。我试图使用法拉第,Typhoeus和Parallel,但这样做我没有遇到功能正常的用例。

理想情况下,我想使用Typhoeus :: Hydra或Faraday,将'data'对象传递给它,并使用数据['url']作为端点汇集数据['postdata'],但我已经空手而归。大多数情况下,我遇到需要有数据数组的情况:

[
    { "url" : "http://...",
      "data" : { "key1" : "value1" },
    { "url" : "http://...",
      "data" : { "key2" : "value2" },
    { "url" : "http://...",
      "data" : { "key3" : "value3" }
]

但我显然希望避免这种重复。

结束目标:将可能100个json主体并行发布到同一个url,每次有限(例如10个)汇集。任何人都可以帮助指导我走正确的道路吗?

免责声明:这是一个内部终点,所以没有任何恶意。

基于tadman的解决方案:

class BatchWrapper
  def initialize(data, offset)
    @data = data
    @offset = offset
  end

  def as_json
    @data['postdata'][@offset]
  end
end

q = Queue.new

data['postdata'].each_index do |i|
  q << BatchWrapper.new(data, i)
end

t = Thread.new do
  n = q.size
  n.times do |i|
    value = q.pop
    res = http.post(data['url'], value.as_json)
    puts res
    puts "consumed #{value.as_json}"
  end
end

t.join

1 个答案:

答案 0 :(得分:1)

通常的策略是将源数据重新映射为更易消化的内容,然后将其分解为多个工作线程或通过某种异步事件驱动方法(例如您在EventMachine中使用)。

线程更容易理解,然后您可以使用Queue结构批量处理每个线程的工作。

将您的作业分解为一系列对象,将这些对象阻塞到队列中,然后启动N个线程来处理这些队列。

由于您正在使用线程,因此可以使用共享数据。例如,您可以拥有一个瘦的包装器对象,给定该格式的结构,捕获您正在发送的偏移量:

class BatchWrapper
  def initialize(data, offset)
    @data = data
    @offset = offset
  end

  def as_json
    @data['postdata'][@offset]
  end
end

然后,只需填写其中一个对象中的每个请求:

q = Queue.new

data['postdata'].each_index do |i|
  q << BatchWrapper.new(data, i)
end

然后你可以在一个工人中旋转队列:

Thread.new do
  while (wrapper = q.pop)
    # Send it...
    make_request(wrapper.to_json)
  end
end

包装器方法允许您准确地组合从主对象共享的数据和特定于请求的数据,以及对数据本身进行任何必要的重组。 as_json方法返回to_json方法最终编码的内容,因此您可以完全控制。