当我的Controller
中的路由被调用时,我需要完成三个任务。现在,我的代码看起来像这样(经过简化):
def set_quotas
TaskOne.new().ex
TaskTwo.new().ex
TaskThree.new().ex
quotas = @user.quotas
render json: quotas, status: 200, each_serializer: Api::V1::QuotaSerializer
end
每个任务都按顺序运行。但是,它们中的几个调用外部服务。因此,完成此调用所需的总时间最终是4-8秒,我们真的希望加快速度。
我想要做的是同时运行这三个任务,但要等到每个任务都完成后才能呈现json
响应。在Rails中实现这一点的最好方法是什么?
发布于 2017-03-23 06:36:01
您可以使用threads来实现这一点。
这里有一个简单的解决方案:
def set_quotas
[
Thread.new { TaskOne.new().ex },
Thread.new { TaskTwo.new().ex },
Thread.new { TaskThree.new().ex }
].each &:join
quotas = @user.quotas
render json: quotas, status: 200, each_serializer: Api::V1::QuotaSerializer
end
然而,在Ruby中使用并发时,有几件事需要注意。首先,也是最重要的是,当您使用线程时,您将受到并发带来的所有复杂性的影响。预计会令人头痛。并发可以非常快地混淆简单的任务。例如,对于您的问题,您需要确保您的三个任务是真正独立的。一个任务依赖于另一个任务的输出吗?有副作用吗?例如,是否将一些数据写入后续作业所依赖的数据库中?如果是这种情况,那么上述方法将不起作用,您需要弄清楚如何适应它们特定的相互依赖关系。
其次,ruby线程是green threads的。(假设您使用的是MRI Ruby,而不是Rubinius或JRuby。)这意味着如果你只想通过ruby线程来完成某些任务的加速。幸运的是,web请求是不会阻塞ruby线程的事情之一,这意味着上面的解决方案将并发地发出所有请求。您应该会看到此解决方案的加速效果。
最后,这在某种程度上是特定于您的用例的,当您的应用程序向第三方发出调用时,通常最佳实践是将这些东西降级给工作人员。对第三方的调用很容易出错,而且返回400秒(500秒,如果你不小心处理错误的话!)给客户。最好是将该工作放入队列中,并给客户端一个响应,本质上是“收到请求,稍后再做”。
考虑到这一切,如果您发现需要比原生ruby线程更强大的东西,请查看concurrent-ruby gem。
@AbM的答案提到了Resque/DJ。有关更一般的解决方案,请查看ActiveJob。对于某些(但不是所有)变体,请参阅ActiveJob adapter list。
https://stackoverflow.com/questions/42951615
复制相似问题