簡體   English   中英

暫停和恢復 F# 異步工作流 (Async<'T>)

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM