【问题标题】:What are the possible reasons the finally of an async { try... finally...} is not being called? Rx Involvedasync { try... finally...} 的 finally 没有被调用的可能原因是什么? Rx 参与
【发布时间】:2023-09-04 22:48:01
【问题描述】:

我有这样的事情:

let a =
    async {
        try
            do! Async.AwaitTask someTask
        finally
            // clean up
    }
Async.Start (a, cancellationTokenSource.Token)

a 中等待的任务完成时,finally 块执行并完成清理,但是当异步 a 被取消时,因为 cancellationTokenSource 被调用 Cancel,清理不会被调用完毕。事实上,我怀疑a 一直在运行。

我真的不知道,所以这里有一个初步的猜测:不,我真的猜不透。

编辑

看来问题出在a 正在等待的任务中。 如果someTask是这样的:

Async.Ignore (Async.AwaitIAsyncResult <| Task.Delay(5000))

那么,没问题:) 但!如果任务是这样的:

vm.Finished.Select(ignore).FirstAsync().ToTask()

vm 是一个视图模型。Finished 是一个事件。基本上,我希望 a 结束,要么是因为取消,要么是因为 Finished 发生在 vm 中。)

然后a拒绝取消或者最后只是跳过了我不知道是哪个。

【问题讨论】:

  • 你能发布一个完整的样本吗?请注意,该任务需要测试它是否已取消。如果没有,它不会取消

标签: asynchronous f# system.reactive cancellation


【解决方案1】:

您需要将CancellationToken传递给ToTask(),否则无法取消。

使用this ToTask overload

【讨论】:

  • 迟到一秒!但是,是的,这就是解决它的方法。好吧,实际上你的答案更明确,所以......
  • 我真正的问题是我调用了错误的重载。我没有意识到我还必须let! ct = Async.CancellationToken
【解决方案2】:

.Net 中的取消是合作的。这意味着一旦任务开始,发送CancellationToken 信号没有实际效果,除非您对其进行监控。

要启用取消,您需要在实际操作中检查CancellationToken.IsCancellationRequested,如果为真,则结束它。或者你可以调用CancellationToken.ThrowIfCancellationRequested 抛出异常,结束操作。

【讨论】:

  • 你是对的。我通过将取消令牌传递给ToTask 来解决它。我遇到了双重麻烦,因为我没有意识到 Async.CancellationToken 返回一个 Async,它在传递给 ToTask 时调用了错误的重载 -.-
最近更新 更多