【问题标题】:Why does this Async F# code not terminate as expected?为什么此 Async F# 代码未按预期终止?
【发布时间】:2021-09-18 17:11:25
【问题描述】:
module Async =

  let forever = Async.FromContinuations ignore

  let withTimeout timeout action =
    async {
      let! child = Async.StartChild (action, timeout)
      return! child
    }

async {
  printfn "Started... "

  do!
    Async.forever
    |> Async.withTimeout 1_000

  printfn "Finished. "
}
|> Async.RunSynchronously

为什么这段代码没有终止?我希望它在 1000 毫秒后完成。

$ dotnet --version
5.0.103

【问题讨论】:

    标签: f#


    【解决方案1】:

    在 F# async 中,检查取消是协作的 - 这意味着各个原始异步操作必须与系统“协作”并检查取消(如果它们执行的操作不会自动传播取消令牌)。

    换句话说,在 F# 异步中,取消检查会自动对 do!let! 等进行,但如果您阻止或从不调用延续,则不会进行检查。

    您可以修改您的forever 以注册取消处理程序并触发操作取消继续:

    let forever : Async<unit> = async {
      let! tok = Async.CancellationToken
      return! Async.FromContinuations(fun (cont, econt, ccont) ->
        tok.Register(fun _ -> ccont(System.OperationCanceledException("cancelled!"))) 
        |> ignore
      )
    }
    

    这样,运行您的示例会打印“正在启动”,然后它会以TimeoutException 失败。如果你真的想打印“完成”文本,你可以这样写:

    async {
      printfn "Started... "
      try
        do! Async.forever |> Async.withTimeout 1_000
      finally 
        printfn "Finished. " }
    |> Async.RunSynchronously
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-29
      • 1970-01-01
      相关资源
      最近更新 更多