在使用Ruby on Rails发送响应之前,我如何等待多个异步操作完成?

[英]How do I wait for multiple asynchronous operations to finish before sending a response in Ruby on Rails?


In Ruby on Rails, I've realized that it's synchronous by nature, and it's up to the developer to do synchronous things asynchronously. In some web dev I do, I have multiple operations beginning, like GET requests to external APIs, and I want them to both start at the same time because one doesn't rely on the result of the other. I found the concurrent-ruby library which seems to work well. By mixing it into a class you create, the class's methods have asynchronous versions which run on a background thread. This lead me to write code like the following, where FirstAsyncWorker and SecondAsyncWorker are classes I've coded, into which I've mixed the Concurrent::Async module, and coded a method named "work" which sends an HTTP request:

在Ruby on Rails中,我已经意识到它本质上是同步的,并且由开发人员异步地执行同步操作。在一些web开发中,我有多个操作开始,比如获取外部api的请求,我希望它们同时开始,因为其中一个不依赖于另一个的结果。我找到了并行ruby库,它似乎运行得很好。通过将它混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这使我编写了如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编码的类,其中混合了Concurrent:::Async模块,并编码了一个名为“work”的方法,该方法发送HTTP请求:

def index
  op1_result = FirstAsyncWorker.new.async.work
  op2_result = SecondAsyncWorker.new.async.work

  render text: results(op1_result, op2_result)
end

However, the controller will implicitly render a response at the end of the action method's execution. So the response gets sent before op1_result and op2_result get values and the only thing sent to the browser is "#".

但是,控制器将在操作方法执行的末尾隐式地呈现响应。因此,响应在op1_result和op2_result获取值之前被发送,发送到浏览器的唯一东西是“#”。

My solution to this so far is to use Ruby threads. I write code like:

到目前为止,我的解决方案是使用Ruby线程。我写这样的代码:

def index
  op1_result = nil
  op2_result = nil

  op1 = Thread.new do
    op1_result = get_request_without_concurrent
  end

  op2 = Thread.new do
    op2_result = get_request_without_concurrent
  end

  # Wait for the two operations to finish
  op1.join
  op2.join

  render text: results(op1_result, op2_result)
end

I don't use a mutex because the two threads don't access the same memory. But I wonder if this is the best approach. Is there a better way to use the concurrent-ruby library, or other libraries better suited to this situation?

我不使用互斥对象,因为这两个线程不访问相同的内存。但我想知道这是否是最好的方法。是否有更好的方法来使用并行ruby库,或者其他更适合这种情况的库?

1 个解决方案

#1


7  

I ended up answering my own after some more research into the concurrent-ruby library. "Future"s ended up being what I was after! Simply put, they execute a block of code in a background thread and attempting to access the Future's calculated value blocks the main thread until that background thread has completed its work. My Rails controller actions end up looking like:

在对并行ruby库进行了更多的研究之后,我终于回答了自己的问题。“未来”最终成了我追求的东西!简单地说,它们在后台线程中执行一个代码块,并试图访问未来的计算值,这会阻塞主线程,直到后台线程完成它的工作。我的Rails控制器动作最终看起来像:

def index
  op1 = Concurrent::Future.execute { get_request }
  op2 = Concurrent::Future.execute { another_request }

  render text: "The result is #{result(op1.value, op2.value)}."
end

The line with "render" blocks until both async tasks have finished, at which point "result" can begin running.

带“呈现”的行会阻塞,直到两个异步任务都完成,这时“结果”可以开始运行。

If anyone is doing this sort of programming, finds this, and wants to see an example of a Rails app implementing both of these async techniques, I've hosted a public example.

如果有人正在做这类编程,找到它,并希望看到一个Rails应用程序实现这两种异步技术的示例,我托管了一个公共示例。


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:http://www.silva-art.net/blog/2016/11/06/2fd1a9510aff6037837c9ce44f08e445.html



 
© 2014-2019 ITdaan.com 粤ICP备14056181号