асинхронное поведение в Fsharp - PullRequest
1 голос
/ 13 февраля 2012

При запуске следующий код

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.

Я ожидаю, что сообщение MSI нажмите любую клавишу после первого сообщения ...

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

Итак, мой вопрос:

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

Ответы [ 2 ]

5 голосов
/ 13 февраля 2012

Как объяснил Джон, метод 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))
5 голосов
/ 13 февраля 2012

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

Post

Асинхронно отправляет сообщение в очередь сообщений MailboxProcessor.

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...