繁体   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