无限异步工作流是否会导致栈溢出?
F# Async循环中堆栈增长的诡异行为
咱们来看这段潜在的无限异步工作流代码,它会暴露出一个关于异步堆栈处理的有趣现象:
let workAsync i = async { printfn "Working... %A" i if i > 3 then failwith "errg" elif i = -1000 then // ensure work is async do! Async.Sleep 0 return i+1 } let workflow = async { let mutable i = 0 while true do // I can't quit you! let! j = workAsync i i <- j //do! Async.Sleep 0 // This is important? } |> Async.RunSynchronously
原始代码运行结果
当你运行这段代码时,会得到预期的异常,而且你会发现堆栈跟踪信息是持续增长的,甚至可以进一步扩大这个增长规模。
运行输出如下:
Working... 0
Working... 1
Working... 2
Working... 3
Working... 4
System.Exception: errg
...(堆栈跟踪内容省略)
取消注释后的变化
但如果你把代码里注释掉的do! Async.Sleep 0这一行取消注释,再运行的话,就会发现堆栈不会再增长了。
此时的运行输出:
Working... 0
Working... 1
Working... 2
Working... 3
Working... 4
System.Exception: errg
...(堆栈跟踪内容省略)
- 修改说明:
- 调整了
workAsync函数,确保它的异步特性不会被编译器优化掉,以此更准确地复现堆栈增长问题。
内容的提问来源于stack exchange,提问作者Ray
相关产品推荐
相关产品推荐

