运行以下代码时
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
我得到以下结果
> 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.
我希望msg按任意键在第一条消息之后出现...
如果我包括睡眠,它确实会发生。
所以我的问题是:
这是一个带走的课程,在使用异步方法时,您不能指望任何特定的顺序。又名,异步中的代码可以从没有特定优先级开始?
答案 0 :(得分:5)
来自mailboxProcessor
的文档(此代码示例所在的文档)
Post
以异步方式将邮件发送到MailboxProcessor的邮件队列。
注意 - Post
没有保证处理 - 这就是异步背后的整个想法。如果你需要等待计算完成,你需要使用PostAndReply
- 虽然此时你会失去多线程的一些好处。
MailboxProcessor
将始终按顺序处理邮件,但除非您等待,否则邮件将无法完成处理
答案 1 :(得分:5)
正如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))