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

Mat*_*lke 5 ruby multithreading asynchronous ruby-on-rails

在Ruby on Rails中,我意识到它本质上是同步的,并且开发人员可以异步地执行同步事务.在我做的一些Web开发中,我开始有多个操作,比如对外部API的GET请求,我希望它们同时启动,因为一个不依赖于另一个的结果.我找到了似乎运行良好的concurrent-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
Run Code Online (Sandbox Code Playgroud)

但是,控制器将在操作方法执行结束时隐式呈现响应.因此,响应在op1_result和op2_result获取值之前发送,并且发送到浏览器的唯一内容是"#".

到目前为止,我的解决方案是使用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
Run Code Online (Sandbox Code Playgroud)

我不使用互斥锁,因为两个线程不访问相同的内存.但我想知道这是否是最佳方法.有没有更好的方法来使用concurrent-ruby库或其他更适合这种情况的库?

Mat*_*lke 10

经过对并发ruby库的更多研究后,我最终回答了自己的问题."未来"最终成为我追求的目标!简单地说,它们在后台线程中执行一段代码,并尝试访问Future的计算值阻塞主线程,直到后台线程完成其工作.我的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
Run Code Online (Sandbox Code Playgroud)

带有"render"的行阻塞,直到两个异步任务完成,此时"result"可以开始运行.

如果有人正在进行这种编程,找到这个,并希望看到实现这两种异步技术的Rails应用程序的示例,我已经举办了一个公开示例.