Async.Start with timeout and cancellationToken?

2019-08-05 17:01发布

问题:

I have an Async<'T> computation that I want to run, and obtain the result 'T.

I only have two requirements:

  1. After certain timeout:TimeSpan has passed, I want the computation/IO to be aborted.
  2. I want to run it with a cancellationToken just in case I want to abort it before timeout has passed.

According to my requirement (1) above, you might think that Async.StartChild is a good candidate because it accepts a timeout parameter, however, it doesn't accept a cancellationToken parameter!

It seems that the other Async. methods in the API that accept a cancellationToken either don't return anything (so I cannot await for the result), or only work for Async<unit>, or don't allow me a way to combine it with Async.StartChild to achieve both of my requirements.

Also, I need to implement this inside an async{} block, which means that using Async.RunSynchronously inside it (just in case you suggest this) would look either problematic or ugly.

Am I overlooking anything?

Thanks!

回答1:

As mentioned in the comments by hvester, you do not need to pass a CancellationToken when starting the Child computation. It will be shared by the Parent and would cancel both, see for example here.

let work dueTime = async{
    do! Async.Sleep dueTime
    printfn "Done" }
let workWithTimeOut timeForWork timeOut = async{
    let! comp = Async.StartChild(work timeForWork, timeOut)
    return! comp }

workWithTimeOut 200 400 |> Async.Start // prints "Done"
workWithTimeOut 400 200 |> Async.Start // throws System.TimeoutException

let cts = new System.Threading.CancellationTokenSource()   
Async.Start(workWithTimeOut 400 200, cts.Token)
System.Threading.Thread.Sleep 100
cts.Cancel() // throws System.OperationCanceledException