【发布时间】:2021-05-27 13:48:52
【问题描述】:
我对 F# 非常陌生,我一直在阅读 F# 的乐趣和利润。在为什么使用 F#? 系列中,有一个 post 描述了异步代码。我遇到了Async.StartChild 函数,我不明白为什么返回值是这样的。
例子:
let sleepWorkflow = async {
printfn "Starting sleep workflow at %O" DateTime.Now.TimeOfDay
do! Async.Sleep 2000
printfn "Finished sleep workflow at %O" DateTime.Now.TimeOfDay
}
let nestedWorkflow = async {
printfn "Starting parent"
let! childWorkflow = Async.StartChild sleepWorkflow
// give the child a chance and then keep working
do! Async.Sleep 100
printfn "Doing something useful while waiting "
// block on the child
let! result = childWorkflow
// done
printfn "Finished parent"
}
我的问题是为什么Async.StartChild 不应该只返回Async<'T> 而不是Async<Async<'T>>?你必须使用let! 两次。 documentation 甚至声明:
此方法通常应用作 let 的直接右侧! F# 异步工作流中的绑定 [...] 以这种方式使用时,每次使用 StartChild 都会启动 childComputation 的实例并返回一个表示计算的完成器对象以等待操作完成。执行时,完成者等待 childComputation 的完成。
在一些测试中,添加了一些睡眠调用,似乎没有初始的let!,子计算永远不会开始。
为什么会有这种返回类型/行为?我习惯了 C# 调用 async 方法总是会立即“启动”任务,即使您不使用 await 它也是如此。事实上,在 C# 中,如果 async 方法不调用任何异步代码,它就会同步运行。
编辑澄清:
这样做有什么好处:
let! waiter = Async.StartChild otherComp // Start computation
// ...
let! result = waiter // Block
与Async.StartChild 返回Async<'T> 相比:
let waiter = Async.StartChild otherComp // Start computation
// ...
let !result = waiter // Block
【问题讨论】:
标签: asynchronous async-await f#