簡體   English   中英

PostAndReply在已處置的郵箱處理器上

[英]PostAndReply on a disposed MailboxProcessor

是否有可能使PostAndAsyncReply在其郵箱處理器處理(或以其他方式停止)時立即返回? 或者是否有一些“模式”/最佳實踐如何安全地使用PostAndReply方法而不會造成死鎖?

現在我遇到的問題是,當郵箱處理器被處理掉后,PostAndAsyncReply永遠不會返回。 使用超時參數不是一個選項,因為我不能等待(除了選擇合理的超時是相當困難或不可能的,因為它取決於太多的因素)。

  [<Test>]
  let ``waiting for a reply from a disposed agent``() =
    use server = MailboxProcessor.Start(fun inbox -> async {
      ()
    })

    (server :> System.IDisposable).Dispose()

    server.PostAndReply (fun reply -> reply) // <- deadlock
    |> ignore)

編輯:我見過的大多數MailboxProcessors示例(包括MSDN上的那些)甚至不介意處置MailboxProcessors。 並且MSDN沒有解釋郵箱處理器在處理時的反應。 是否沒有必要處置它們?

取消暫掛的PostAndReply調用沒有內置支持,但您可以實現此功能。 要處理處理,你可以在try .. finally包裝郵箱的主體。 finally塊中,您可以以某種方式表示郵箱處理器已停止。 以下使用取消令牌源:

let disposed = new System.Threading.CancellationTokenSource()
let server = MailboxProcessor<AsyncReplyChannel<obj>>.Start(fun inbox -> 
  async { 
    try 
      // The normal body of the mailbox processor goes here
      do! Async.Sleep(1000)
      printfn "done"
    finally 
      // Cancel all pending calls post and reply
      disposed.Cancel()
   })

// Dispose the mailbox processor    
(server :> System.IDisposable).Dispose()

// When sending message, we use 'StartAsTask' and set a cancellation token,
// so that the work is stopped when the mailbox processor finishes
let wait = server.PostAndAsyncReply(fun reply -> reply)
let task = Async.StartAsTask(wait, cancellationToken = disposed.Token)
printfn "%A" task.Result

要記住兩件事:

  • 如果郵箱處理器正在運行一些長時間運行的工作(比如在上面休眠),那么在完成此操作后將進行處理(這是因為異步工作流的性質 - 它們沒有強制取消計算)

  • 我必須使用StartAsTask而不是RunSynchronously來在最后啟動任務。 由於某種原因(不太確定),使用RunSynchronously似乎不會取消計算。

您可以輕松地將其包裝在內部使用MailboxProcessor某個類中,公開類似的界面並添加此功能 - 但這對於單個答案來說有點太多了!

要回答有關Dispose的問題,我不完全確定其行為是什么,但處置郵箱處理器會釋放一個內部AutoResetEvent (請參閱源代碼 ),用於表示郵件已到達。 我想這只是意味着郵箱處理器不會接受任何進一步的消息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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