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