编写异步例程:选用start还是Promise.then?
Raku异步例程:start块 vs 链式Promise的性能分析
问题背景
你提供了JavaScript的async/await异步函数示例,随后在Raku中实现了两种等价异步逻辑:
- 使用
start { }包装协程,配合await编写异步代码 - 使用Promise链式调用(
.then)实现逻辑
通过基准测试发现链式Promise速度更快,但代码复杂度更高,因此提出两个问题:
问题1:当前链式Promise确实更快,还是基准测试存在误导?
你的基准测试存在明显误导,原因在于test-then的写法不符合真正的异步Promise链式调用规范:
sub test-then { Promise.kept(42).then({ my $data := $_.result; my $second-data := $data.is-prime; # 这里调用了.result,会同步阻塞当前线程等待内层Promise完成 Promise.kept.then({ my $result := $second-data == False ?? 'ok' !! 'err'; $result; }).result; # 关键问题:同步阻塞 }) }
在then回调中调用.result会强制同步等待内层Promise完成,这相当于把异步逻辑变成了同步执行,完全跳过了Raku异步调度器的协程挂起/恢复流程。而test-start中的await会正常触发协程挂起,让调度器处理其他任务,这部分调度开销是test-then没有的,因此测试结果中链式Promise更快,但这是测试代码人为制造的差异,而非两种异步写法的真实性能差距。
如果修正test-then为标准的链式异步写法(去掉.result,让Promise链自然异步流转):
sub test-then { Promise.kept(42).then({ my $data := $_.result; my $second-data := $data.is-prime; Promise.kept.then({ $second-data == False ?? 'ok' !! 'err'; }) }) }
此时两种写法的性能差距会大幅缩小,因为都要经过异步调度器的处理。
问题2:未来Rakudo优化后,start方式能否追上链式Promise的速度?
完全有可能,甚至在优化后start+await的写法性能会更优,原因如下:
- 底层实现逻辑趋同:
start { }配合await本质是Raku编译器将协程代码转换成状态机,和链式Promise的底层调度逻辑是同源的,两者的核心开销都是异步调度器的协程管理。 - 当前差距的来源:当前
start+await的性能劣势主要来自协程挂起/恢复的额外开销,这部分是Rakudo实现层面的优化空间,而非语言设计的固有缺陷。 - 写法的可读性优势:
start+await更接近JavaScriptasync/await的直观写法,编译器可以针对这种结构化的异步代码做更多优化(比如减少不必要的协程切换),而链式Promise的嵌套写法优化空间相对有限。
从长远来看,Rakudo对协程调度的持续优化(比如减少上下文切换开销、优化await的状态机生成)会让start+await的性能逐步追上甚至超过链式Promise。
内容的提问来源于stack exchange,提问作者fingolfin
相关产品推荐
相关产品推荐

