Ruby中是否有类似于JS 'Promise.all()'的东西?



以下是应优化的代码:

def statistics
  blogs = Blog.where(id: params[:ids])
  results = blogs.map do |blog|
    {
      id: blog.id,
      comment_count: blog.blog_comments.select("DISTINCT user_id").count
    }
  end
  render json: results.to_json
end

每个SQL查询的成本约为200ms。如果我有10个博客文章,则此功能将需要2次,因为它同步运行。我可以使用GROUP BY来优化查询,但是我首先将其放在一边,因为该任务可能是第三方请求,我对Ruby如何处理async很感兴趣。

在JavaScript中,当我想派遣多个异步作品并等待所有这些作品时,我可以使用Promise.all()。我想知道Ruby语言解决此问题的选择是什么。

我需要这种情况的线程吗?在Ruby中这样做是安全的吗?

有多种方法可以在Ruby中解决此问题,包括承诺(由Gems启用(。

JavaScript使用事件循环和事件驱动的I/O完成异步执行。有事件库可以在Ruby中完成同样的事情。最受欢迎的是eventmachine

您提到,线程也可以解决此问题。线程安全是一个大主题,在Ruby(MRI,Jruby等(的不同风味中的不同线模型更加复杂。总而言之,我只是说当然可以安全地使用线程……有时候很难。但是,当用于阻止I/O(喜欢API或数据库请求(时,线程可能非常有用且相当直接。带有线程的解决方案可能看起来像这样:

# run blocking IO requests simultaneously
thread_pool = [
  Thread.new { execute_sql_1 },
  Thread.new { execute_sql_2 },
  Thread.new { execute_sql_3 },
  # ...
]
# wait for the slowest one to finish
thread_pool.each(&:join)

您还可以访问其他货币模型,例如Actor模型,异步类,承诺以及由concurrent-ruby等宝石启用的其他模型。

最后,Ruby并发可以采用多个过程的形式,这些过程通过内置机制(DRB,插座等(或通过分布式消息经纪(Redis,RabbitMQ等(进行交流。

好吧,概括:

您有一个数据 data列表,并希望不同步地对该数据进行操作。假设列表中所有条目的操作都是相同的,则可以执行此操作:

data = [1, 2, 3, 4] # Example data
operation = -> (data_entry) { data * 2 } # Our operation: multiply by two
results = data.map{ |e| Thread.new(e, &operation) }.map{ |t| t.value }

将其拆开:

data = [1, 2, 3, 4]

这可能是从数据库ID到URI的任何东西。在此处使用数字为简单。

operation = -> (data_entry) { data * 2 }

lambda的定义,该lambda采用一个参数并对其进行一些计算。这可能是API调用,SQL查询或任何其他需要一些时间完成的操作。同样,为简单起见,我只是将数字乘以2。

results =

此数组将包含所有异步操作的结果。

data.map{ |e| Thread.new(e, &operation) }...

对于数据集中的每个条目,请催生运行operation并以参数传递条目的线程。这是lambda中的data_entry参数。

...map{ |t| t.value }

从每个线程中提取值。这将等待线程首先完成,因此在此行结束时,您的所有数据都将在那里。

lambdas

lambdas实际上只是荣耀的块,如果您通过错误的参数,会引起错误。语法-> (arguments) {code}只是Lambda.new { |arguments| code }的句法糖。

当一种方法接受Thread.new { do_async_stuff_here }之类的块时,您也可以通过lambda或Proc对象,前缀为&,并且将以相同的方式处理。

一定要在一个数据库中进行计数:

blogs = Blog
  .select('blogs.id, COUNT(DISTINCT blog_comments.user_id) AS comment_count')
  .joins('LEFT JOIN blog_comments ON blog_comments.blog_id = blogs.id')
  .where(comments: { id: params[:ids] })
  .group('blogs.id')
results = blogs.map do |blog|
  { id: blog.id, comment_count: blog.comment_count }
end
render json: results.to_json

您可能需要根据数据库中的表格来更改陈述,因为我只是用您的协会的名称猜测。

最新更新