我有一个用ruby编写的http客户端,可以对url发出同步请求。但是,为了快速执行多个请求,我决定使用eventmachine。我的想法是
将所有请求排队并使用eventmachine执行它们。
class EventMachineBackend
...
...
def execute(request)
$q ||= EM.Queue.new
$q.push(request)
$q.pop {|request| request.invoke}
EM.run{EM.next_tick {EM.stop}}
end
...
end
请原谅我使用了全局队列变量。我稍后会重构它。我在
EventMachineBackend#execute
中所做的是使用eventmachine队列的正确方法吗?我在实现中看到的一个问题是它本质上是同步的。我推送一个请求,弹出并执行该请求,然后等待它完成。
有人能建议更好的实施吗?
最佳答案
您的请求逻辑必须是异步的才能与eventmachine一起工作,我建议您使用em-http-request。您可以找到an example on how to use it here,它显示了如何并行运行请求。并行运行多个连接的更好接口是来自同一个gem的MultiRequest class。
如果要将请求排队,并且只并行运行固定数量的请求,可以执行以下操作:
EM.run do
urls = [...] # regular array with URLs
active_requests = 0
# this routine will be used as callback and will
# be run when each request finishes
when_done = proc do
active_requests -= 1
if urls.empty? && active_requests == 0
# if there are no more urls, and there are no active
# requests it means we're done, so shut down the reactor
EM.stop
elsif !urls.empty?
# if there are more urls launch a new request
launch_next.call
end
end
# this routine launches a request
launch_next = proc do
# get the next url to fetch
url = urls.pop
# launch the request, and register the callback
request = EM::HttpRequest.new(url).get
request.callback(&when_done)
request.errback(&when_done)
# increment the number of active requests, this
# is important since it will tell us when all requests
# are done
active_requests += 1
end
# launch three requests in parallel, each will launch
# a new requests when done, so there will always be
# three requests active at any one time, unless there
# are no more urls to fetch
3.times do
launch_next.call
end
end
请注意Emptor,上面的代码很可能遗漏了一些细节。
如果您认为很难遵循我的示例中的逻辑,欢迎来到事件编程的世界。编写可读的事件代码真的很难。一切都在倒退。有时从结尾开始阅读会有帮助。
我假设您在开始下载后不想添加更多请求,这与问题代码中的情况不同,但如果您想,可以重写我的代码以使用
EM::Queue
而不是常规数组,并删除不使用EM.stop
的部分,因为您不会停止。您也可以删除跟踪活动请求数的代码,因为这与此无关。重要的部分是这样的:launch_next = proc do
urls.pop do |url|
request = EM::HttpRequest.new(url).get
request.callback(&launch_next)
request.errback(&launch_next)
end
end
另外,请记住,我的代码实际上与响应没有任何关系。响应将作为参数传递给
when_done
例程(在第一个示例中)。对于成功和错误,我也会做同样的事情,这是您在实际应用程序中可能不想做的。关于ruby - Ruby Eventmachine排队问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4990170/