[英]Suspend and resume F# asynchronous workflows (Async<'T>)
有沒有一種通用的方法來獲得對任意異步工作流執行的外部控制,用於暫停和恢復? 類似於 CancellationToken,但更像是 SuspendResumeToken,其中可以簡單地執行以下操作:
let suspendResumeToken = new SuspendResumeToken()
Async.Start(longRunningAsync, suspendResumeToken=suspendResumeToken)
...
// meanwhile
async {
do! suspendResumeToken.SuspendAsync()
printfn "Suspended longRunningAsync!"
do! suspendResumeToken.ResumeAsync()
printfn "Resumed longRunningAsync!"
}
我可以通過在每次迭代或遞歸步驟檢查這樣的標記來模擬遞歸或迭代函數的行為,但由於異步工作流具有自然的屈服點,因此將其內置作為控制異步的一般方法是很自然的調度。
使用事件可以很容易地實現像SuspendResumeToken
這樣的東西。 您可以定義一個事件,在計算中等待它,然后從外部觸發它以恢復計算:
let suspendEvent = new Event<_>()
let awaitSuspendResume () = suspendEvent.Publish |> Async.AwaitEvent
let longRunningAsync () = async {
do! awaitSuspendResume ()
printfn "Suspended longRunningAsync!"
do! awaitSuspendResume ()
printfn "Resumed longRunningAsync!"
}
Async.Start(longRunningAsync())
suspendEvent.Trigger() // Run this multiple times to make a step
沒有辦法在async
的屈服點自動獲得它,但你可以定義你自己的計算構建器,它與async
完全一樣,除了它在Bind
操作中插入檢查(可能還有其他一些地方 - 你有想想你到底想在哪里做這件事):
let suspendEvent = new Event<_>()
let awaitSuspendResume () = suspendEvent.Publish |> Async.AwaitEvent
type SuspendAsyncBuilder() =
// Custom 'Bind' with the extra check
member x.Bind(a:Async<'T>, f:'T -> Async<'R>) : Async<'R> =
async {
let! av = a
do! awaitSuspendResume()
return! f av }
// All other operations just call normal 'async'
// (you will need to add many more here!)
member x.Zero() = async.Zero()
let sasync = SuspendAsyncBuilder()
let longRunningAsync () = sasync {
do! Async.Sleep(0)
printfn "Suspended longRunningAsync!"
do! Async.Sleep(0)
printfn "Resumed longRunningAsync!"
}
Async.Start(longRunningAsync())
suspendEvent.Trigger()
請注意,這只會檢查周圍!
喜歡do!
所以我必須在示例中插入一個Sleep
才能使其工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.