f# - PostAndReply 在已处理的 MailboxProcessor 上

标签 f# mailboxprocessor

当其 MailboxProcessor 被处理(或以其他方式停止)时,是否可以让 PostAndAsyncReply 立即返回?或者是否有一些关于如何安全地使用 PostAndReply 方法而不造成死锁的“模式”/最佳实践?

现在我遇到的问题是 PostAndAsyncReply 在 MailboxProcessor 被处理后永远不会返回。使用 timeout 参数不是一种选择,因为我迫不及待(此外,选择合理的超时非常困难或不可能,因为它取决于太多因素)。

  [<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)

编辑:我见过的大多数邮箱处理器示例(包括 MSDN 上的示例)甚至不介意处理邮箱处理器。并且 MSDN 没有解释 MailboxProcessors 在被处理时如何 react 。没有必要处置它们吗?

最佳答案

没有对挂起取消的内置支持 PostAndReply调用,但您可以实现这一点。如需处理处置,可将邮箱主体包裹在try .. finally中。 .在 finally阻止,您可以以某种方式发出邮箱处理器已停止的信号。以下为此使用取消 token 源:

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

有两件事要记住:
  • 如果邮箱处理器正在运行一些长时间运行的工作(如上面的 sleep ),那么在完成后会发生处理(这是因为异步工作流的性质 - 它们不会强制取消计算)
  • 我不得不使用 StartAsTask而不是 RunSynchronously最后开始任务。出于某种原因(不太确定),使用 RunSynchronously似乎没有取消计算。

  • 你可以很容易地把它包装在一些使用 MailboxProcessor 的类中。在内部,公开类似的界面并添加此功能 - 但对于一个单一的答案来说有点太多了!

    回答您关于 Dispose 的问题,我不完全确定行为是什么,但处理邮箱处理器会处理内部 AutoResetEvent (请参阅 the source code )用于表示消息已到达。我想这只是意味着邮箱处理器不会接受任何进一步的消息。

    关于f# - PostAndReply 在已处理的 MailboxProcessor 上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18312987/

    相关文章:

    memory-leaks - Microsoft.FSharp.Control.Mailbox 中的内存泄漏?

    asynchronous - MailboxProcessor.Dispose 不会使对象 GC 可收集

    f# - 书上有一个F#示例,但我什至无法编译

    Linq 类似函数 GroupMultipleValBy

    types - F# 如何从其他模块推断类型和标签?

    f# - 与 MailboxProcessor 和 Task 的交互永远挂起

    asynchronous - F# 事件在异步工作流中不起作用

    multithreading - 使用带有回复 channel 的 MailboxProcessor 来创建按顺序返回值的有限代理

    f# - WebPart 用于使用 Suave 将请求转发到另一台服务器?

    f# - 可区分联合内的匿名记录类型