是否可以在邮箱中等待,遵循代码在f#Interactive中工作,但是有没有办法在应用程序或单位测试中等待它?
[<TestMethod>]
member this.TestMailboxProcessor() =
let mailboxProcessor = MailboxProcessor<string>.Start(fun inbox ->
async {
while true do
let! msg = inbox.Receive()
printfn "agent got message %s" msg // too late, UnitTest exits
}
)
mailboxProcessor.Post "ping"
Console.WriteLine "message posted" // I see this in the console
Assert.IsTrue(true)
在这种情况下完全不可能,但是您可以定义消息类型以包含asyncreplyplyplyplychannel&lt;'t>,然后允许您使用MailboxProcessor.postandreply,而不是帖子。这样,调用代码可以(同步或异步(等待响应值,或者至少指示处理已完成。
您的修改源代码可能看起来像:
[<TestMethod>]
member this.TestMailboxProcessor() =
let mailboxProcessor =
MailboxProcessor<string * AsyncReplyChannel<unit>>.Start(fun inbox ->
async {
while true do
let! msg, replyChannel = inbox.Receive()
printfn "agent got message %s" msg
(*
Reply takes a value of the generic param of
AsyncReplyChannel<'t>, in this case just a unit
*)
replyChannel.Reply()
}
)
(*
You can't create an AsyncReplyChannel<'t> value, but this does it for you.
Also always, always use timeouts when awaiting message replies.
*)
mailboxProcessor.PostAndReply(
(fun replyChannel -> "ping", replyChannel),
timeout = 1000)
(* This gets printed only after the message has been posted and processed *)
Console.WriteLine "message posted"
Assert.IsTrue(true)
MailboxProcessors是有点棘手的话题,因此请确保您始终使用超时,否则在代码中出现错误或杀死消息循环的例外,您的代码将永远存在。在测试中不好,生产更糟。
您应该使用PostAndAsyncReply
或PostAndReply
(阻止版本(
let replyAgent = MailboxProcessor.Start(fun inbox ->
let rec loop() =
async {
let! (replyChannel: AsyncReplyChannel<_>), msg = inbox.Receive()
replyChannel.Reply (sprintf "replied for message: %A" msg)
return! loop()
}
loop() )
let reply = replyAgent.PostAndReply(fun replCh -> replCh, "Hi")
printfn "%s" reply //prints "replied for message: Hi"