运行以下代码时
open System
open Microsoft.FSharp.Control
type Message(id, contents) =
static let mutable count = 0
member this.ID = id
member this.Contents = contents
static member CreateMessage(contents) =
count <- count + 1
Message(count, contents)
let mailbox = new MailboxProcessor<Message>(fun inbox ->
let rec loop count =
async { printfn "Message count = %d. Waiting for next message." count
let! msg = inbox.Receive()
printfn "Message received. ID: %d Contents: %s" msg.ID msg.Contents
return! loop( count + 1) }
loop 0)
mailbox.Start()
mailbox.Post(Message.CreateMessage("ABC"))
mailbox.Post(Message.CreateMessage("XYZ"))
//System.Threading.Thread.Sleep(500)
Console.WriteLine("Press any key...")
Console.ReadLine() |> ignore
Run Code Online (Sandbox Code Playgroud)
我得到以下结果
> Press any key...
Message count = 0. Waiting for next message.
Message received. ID: 1 Contents: ABC
Message count = 1. Waiting for next message.
Message received. ID: 2 Contents: XYZ
Message count = 2. Waiting for next message.
Run Code Online (Sandbox Code Playgroud)
我希望msg按任意键在第一条消息之后出现...
如果我包括睡眠,它确实会发生.
所以我的问题是:
是拿走的教训,采用异步方法时,你不能指望任何特定顺序的这一点.又是,async中的代码可以从没有特定的优先级开始?
来自mailboxProcessor(此代码示例来自)的文档
Post以异步方式将消息发送到MailboxProcessor的消息队列.
注意 - Post没有关于处理的保证 - 这是异步背后的整个想法.如果您需要等待计算完成,则需要使用PostAndReply- 尽管此时您将失去多线程的一些好处.
该MailboxProcessor公司将始终按顺序处理消息,但除非你等着吧,消息将无法完成的处理
如John所解释的,该Post方法只是将消息发布到邮箱以供稍后处理.可以在发送方线程上发生其他事情之前处理该消息,但它可能不会 - 这仅仅取决于线程调度,并且无法控制该消息.
如果要将邮件发送到邮箱并等待结果,则需要使用PostAndReply方法(或者,更好地使用PostAndAsyncReply异步工作流来避免阻塞).这是一个例子:
/// The message carries AsyncReplyChannel<unit>, which is used to
/// notify the caller that the message was processed.
type Message =
| Message of int * string * AsyncReplyChannel<unit>
let mailbox = new MailboxProcessor<Message>(fun inbox ->
let rec loop count =
async { printfn "Message count = %d. Waiting for next message." count
// Receive & process the message
let! (Message(id, contents, repl)) = inbox.Receive()
printfn "Message received. ID: %d Contents: %s" msg.ID msg.Contents
// Notify the caller that processing has finished
repl.Reply()
return! loop( count + 1) }
loop 0)
mailbox.Start()
// Send message and wait for reply using 'PostAndReply' method
mailbox.PostAndReply(fun chnl -> Message(0, "ABC", chnl))
mailbox.PostAndReply(fun chnl -> Message(0, "XYZ", chnl))
Run Code Online (Sandbox Code Playgroud)