Ruby Async Gem基础用法示例与顶层调用阻塞问题解答
async gem 核心运行逻辑与基础用法规范
两段代码的行为差异原因
第一个示例无法实现并行的核心原因是:每次在顶层调用Async时,都会独立创建并运行reactor,且会阻塞到当前reactor的任务执行完成后才会进入下一次循环,本质是10个串行的独立任务,总耗时接近10*1.6s。
顶层与嵌套Async调用的行为差异
Async调用的执行逻辑完全取决于当前上下文是否存在运行中的reactor:
- 无已运行reactor(多为顶层调用场景):
Async会先创建reactor,把传入的代码块作为根任务运行,阻塞当前线程直到reactor内所有任务执行完毕- 已有运行中reactor(嵌套在其他
Async代码块内的场景):Async只会把传入的代码块作为子任务提交给当前reactor调度,不会阻塞当前执行流,子任务会和其他同级别子任务并行调度。
标准基础用法规范
1. 单个顶层Async块作为异步入口
所有异步任务都需要嵌套在同一个顶层Async块内部,避免重复创建独立reactor导致串行执行:
require 'async' require 'httparty' # 单个顶层Async块作为异步程序唯一入口 Async do # 内部所有Async调用都是非阻塞的子任务,由同一个reactor统一调度 10.times do |i| Async do resp = HTTParty.get("https://httpbin.org/delay/1.6") puts "任务#{i}执行完成,状态码:#{resp.code}" end end end # 顶层Async块外的代码会等待所有异步任务完成后才执行 puts "所有任务执行完毕"
2. 显式等待子任务(可选)
如果需要获取子任务的返回值、或者控制子任务的执行顺序,可以调用任务对象的#wait方法:
Async do # 保存子任务对象 task = Async do HTTParty.get("https://httpbin.org/delay/1.6") end # 等待子任务完成并获取返回值 resp = task.wait puts "请求结果:#{resp.body}" end
3. IO操作无需额外改造
Ruby 3.0+内置的Fiber调度机制会自动拦截标准库的阻塞IO操作(HTTP请求、文件读写、数据库查询等),原有IO代码不需要修改即可实现异步调度。
内容的提问来源于stack exchange,提问作者Christopher Oezbek
相关产品推荐
相关产品推荐

