2012-02-12 2 views
1

При выполнении следующего кодаасинхронной в FSharp

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. 

Я ожидаю сообщ пресс Anykey прийти несколько после первого сообщения ...

И если я включаю сон, это действительно происходит.

Так что мой вопрос:

ли забрать урок это, что вы не можете ожидать какую-либо конкретная упорядоченности при использовании методов асинхронных. aka, код внутри async может начаться без специального приоритета?

ответ

5

Из документов для mailboxProcessor (где этот образец кода составляет от)

Post

сообщений сообщение в очередь сообщений MailboxProcessor, асинхронно.

Примечание - Post не делает никаких гарантий относительно обработки - вот и вся идея асинхронизации. Если вам нужно дождаться завершения вычислений, вам нужно использовать PostAndReply - хотя в этот момент вы теряете часть преимуществ многопоточности.

MailboxProcessor всегда будет обрабатывать сообщения в порядке, но если вы не ждать его, сообщения не будут закончены обработке

+0

точно. это лежит в основе концепции. никаких гарантий в асинхронном режиме, это контроль снаружи, с определенными командами. Спасибо. – nicolas

5

Как пояснил Джон, метод 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)) 
+0

Большое спасибо за этот подробный ответ. это будет полезно для других асинхронных новичков. – nicolas

Смежные вопросы