如何让Ruby Async gem版本1.xx并行运行任务?

nxowjjhe  于 2023-06-22  发布在  Ruby
关注(0)|答案(1)|浏览(107)

我尝试在ruby 2.7中使用Async gem,它只支持1.xx版本。我安装了最新的1.xx版本(1.31.0)。
当我从documentation运行下面的简单示例时,它应该并行运行所有3个子任务并在1秒内完成,但它似乎顺序运行它们并在3秒内完成。
如果我使用ruby 3.1和最新的Async gem版本(2.6.1)运行相同的示例,它似乎并行运行它们,并在1秒内完成。
我最初的想法是gem中有一个bug,所以我卸载了gem并安装了几个后台版本,它们的行为都是一样的,这让我觉得我误解了1.xx版本的一些东西。

require "async"

Async do
  3.times do |i|
    Async do
      sleep 1
      puts "Hello World #{i}"
    end
  end
end

更新

使用task.sleep确实允许所有的sleep并行发生,但似乎这可能是一个特例(sleep的特殊版本被称为)?

Async do |task|
  3.times do |i|
    Async do
      start = Time.now
      puts "starting task #{i} at #{start.to_f}"
      (0..1000000/((i+1)*10000)).reduce(:*)
      done = Time.now
      puts "finished task #{i} at #{done.to_f},  took #{done - start}"
    end
  end
end

一个稍微真实一点的例子再次显示了串行执行。

starting task 0 at 1686603935.7939696
finished task 0 at 1686603935.7940578,  took 8.799e-05
starting task 1 at 1686603935.7941055
finished task 1 at 1686603935.7941372,  took 3.1856e-05
starting task 2 at 1686603935.7941997
finished task 2 at 1686603935.7942228,  took 2.3047e-05

我还没有在Ruby 3.1上用2.xx版本的gem尝试过这个。

roqulrg3

roqulrg31#

我有在Ruby 2.7.5中使用async gem的经验。例如,在原始代码中,如果向速度较慢的Web服务器发出请求,则任务将并发运行。

require 'async'
require 'open-uri'

uri = 'https://nghttp2.org/httpbin/delay/5'
puts "Start: #{Time.now}"

Async do
  3.times do |i|
    Async do
      puts "Before Request #{i} - #{Time.now}"
      URI.open uri
      puts "After Request #{i} - #{Time.now}"
    end
  end
end

puts "End: #{Time.now}"

当你运行上面的代码时,它会产生以下结果:

Start: 2023-06-13 07:07:22 +0700
Before Request 0 - 2023-06-13 07:07:22 +0700
Before Request 1 - 2023-06-13 07:07:22 +0700
Before Request 2 - 2023-06-13 07:07:22 +0700
After Request 1 - 2023-06-13 07:07:28 +0700
After Request 0 - 2023-06-13 07:07:28 +0700
After Request 2 - 2023-06-13 07:07:33 +0700
End: 2023-06-13 07:07:33 +0700

在您的sleep案例中,您应该将sleep替换为task.sleep

require 'async'

puts "Start: #{Time.now}"

Async do
  3.times do |i|
    Async do |task|
      task.sleep 5
      puts "Hello World #{i} - #{Time.now}"
    end
  end
end

puts "End: #{Time.now}"

当你运行上面的代码时,它会产生以下结果:

Start: 2023-06-12 20:38:24 +0700
Hello World 0 - 2023-06-12 20:38:29 +0700
Hello World 1 - 2023-06-12 20:38:29 +0700
Hello World 2 - 2023-06-12 20:38:29 +0700
End: 2023-06-12 20:38:29 +0700
并行宝石

作为替代方案,您可以通过使用parallel gem来实现相同的目的。

require 'parallel'
require 'open-uri'

uris = ['https://nghttp2.org/httpbin/delay/5', 'https://nghttp2.org/httpbin/delay/3', 'https://nghttp2.org/httpbin/delay/1']
puts "Start: #{Time.now}"

results = Parallel.map(uris, in_threads: 3) do |uri|
  puts "Before Request #{uri} - #{Time.now}"
  URI.open uri
  puts "After Request #{uri} - #{Time.now}"
end

puts "End: #{Time.now}"

结果:

Start: 2023-06-13 07:25:12 +0700
Before Request https://nghttp2.org/httpbin/delay/5 - 2023-06-13 07:25:12 +0700
Before Request https://nghttp2.org/httpbin/delay/3 - 2023-06-13 07:25:12 +0700
Before Request https://nghttp2.org/httpbin/delay/1 - 2023-06-13 07:25:12 +0700
After Request https://nghttp2.org/httpbin/delay/3 - 2023-06-13 07:25:16 +0700
After Request https://nghttp2.org/httpbin/delay/1 - 2023-06-13 07:25:16 +0700
After Request https://nghttp2.org/httpbin/delay/5 - 2023-06-13 07:25:17 +0700
End: 2023-06-13 07:25:17 +0700

相关问题