.net 取消执行阻塞同步工作的异步工作流

.net 取消执行阻塞同步工作的异步工作流,.net,f#,.net,F#,我不确定是否可以这样做,但我有一个执行阻塞操作的异步工作流。如果它已经运行了很长一段时间,包括当前正在执行工作流的线程,我想取消它 下面是我的测试用例: let counter = ref 0 let work = async { let computation = async { System.Threading.Interlocked.Increment(counter) |> ignore let blockingWork = Async.Sl

我不确定是否可以这样做,但我有一个执行阻塞操作的异步工作流。如果它已经运行了很长一段时间,包括当前正在执行工作流的线程,我想取消它

下面是我的测试用例:

let counter = ref 0
let work = async {
    let computation = async {
        System.Threading.Interlocked.Increment(counter) |> ignore
        let blockingWork = Async.Sleep(2000) |> Async.RunSynchronously
        System.Threading.Interlocked.Increment(counter) |> ignore
    }
    do! computation
}

use cts = new System.Threading.CancellationTokenSource(1000)
let tryCancelled = Async.TryCancelled(work, fun _ -> printf "Cancelled")
do Async.Start(tryCancelled, cts.Token) 
System.Threading.Thread.Sleep(3000) //Simulate other work
counter.contents |> should equal 1

问题是工作流被成功取消,补偿函数被调用,但计算将继续并递增计数器…

使用Do在异步上下文中执行阻塞工作!砌块工程

let counter = ref 0
let work = async {
    let computation = async {
        System.Threading.Interlocked.Increment(counter) |> ignore
        let blockingWork = Async.Sleep(2000) 
        do! blockingWork 
        System.Threading.Interlocked.Increment(counter) |> ignore
    }
    do! computation
}

let doit() =
    use cts = new System.Threading.CancellationTokenSource(1000)
    let tryCancelled = Async.TryCancelled(work, fun _ -> printf "Cancelled")
    do Async.Start(tryCancelled, cts.Token) 
    System.Threading.Thread.Sleep(3000) //Simulate other work
    counter.contents // |> should equal 1

doit() 

如果您使用
do!调用其他异步,async内部的取消支持基本上是有效的
让我来和一些结构,如
while
-它不会中断同步。电话!因此,您必须将令牌传递到同步。阻止并检查它是否被取消,或者您必须使用线程执行某些操作并中止(不推荐!)-顺便说一句:这假设睡眠仅用于演示-如果不是,您会得到答案;)另外:您没有取消示例中的令牌-这当然也会导致您的假设无效;)@卡斯滕好吧我想我明白了。。。我担心的是,我需要以某种方式中止线程,因为我需要执行的同步工作可能会花费很多时间,并且它会调用一个我无法控制的外部库……老实说,在大多数情况下,这是一个不可能的事,因为如果您杀死的代码处于任何优雅的状态,您将无法控制任何事情——但是如果您真的感觉到你必须-你可以订阅tokens事件并杀死从那里创建的线程。。。但同样不推荐(也要确保取消订阅…我直接看到了严重的内存泄漏)我无法为您回答这个问题-老实说,您不应该陷入无论发生什么都必须中止线程的情况-我建议您寻找一种方法来分解计算或使其了解取消令牌是的,异步。睡眠用于演示。您可以将其更改为Thread.Sleep(),并将管道跳过为Async.RunSynchronously