如何通过超时停止等待TaskCompletionSource周围的异步包装?

时间:2016-02-24 17:25:41

标签: asynchronous f# task-parallel-library

假设我有一些系统“BlackBox”,我无法改变,我想尝试用它做2秒,如果它不能完成 - 停止并继续其他应用:

let log msg =
    let timestamp = (System.DateTime.UtcNow.ToString("o"))
    printfn "%s: %s" timestamp msg

type BlackBox() =
    let tcs = new System.Threading.Tasks.TaskCompletionSource<bool>()

    let work () = async {
        log "work started"
        let! result = tcs.Task |> Async.AwaitTask
        log "work finished"
        return result }

    member x.DoWork    () = work ()
    member x.SetResult () = tcs.TrySetResult(true)

let tryDoWork (box:BlackBox) = async {
    try
        log "operration starting with 2sec timeout"
        Async.RunSynchronously(box.DoWork(), timeout = 2000) |> ignore
        log "operration succeeded"
    with
    | ex -> log "operation timedout" }

let sut = BlackBox()
tryDoWork sut |> Async.Start
log "waiting 5sec before setting task result"
Async.Sleep 5000 |> Async.RunSynchronously
log "setting task result"
sut.SetResult() |> ignore
​
​
// Output is:
// ------------------------------------
// 2016-02-24T16:45:11.0302884Z: waiting 5sec before setting task result
// 2016-02-24T16:45:11.0302884Z: operration starting with 2sec timeout
// 2016-02-24T16:45:11.0351932Z: work started
// 2016-02-24T16:45:16.0322394Z: setting task result
// 2016-02-24T16:45:16.0351731Z: work finished
// 2016-02-24T16:45:16.0361528Z: operation timedout

Async.RunSyncronously with timeout在2秒后抛出TimeoutException,但不是在这种情况下,因为内部BlackBox正在等待Task完成。

1 个答案:

答案 0 :(得分:2)

TCS(来自@ Carsten的评论)对我有用,因为我无法访问BlackBox内部,并且无法在不更改应用程序的整个设计且需要添加超时的机制的情况下更改它,不需要取消更长的任务

其他提议的事情是:

@kevin:

  

snippet by Eirik TsarpalisAsync.AwaitIAsyncResult

并且@kevin注意到我的例子没有按预期工作的原因是

  

RunXynchronously with timeout依赖于给定的async可取消

我发现的另一件事是how to cancel non-cancelable async operations