简体   繁体   English

F# MailboxProcessor 异步混乱打印语句

[英]F# MailboxProcessor async messed print statements

I am trying to make a bar simulator that is processing orders.我正在尝试制作一个正在处理订单的酒吧模拟器。 The message that is sent to the agent is of this type.发送给代理的消息属于这种类型。

type DTGCafeMessage =
    | OrderDrink of Drink * float
    | LeaveAComment of string

The agent is a bar class implemented below.代理是下面实现的一个吧class。

type Bar() =
    let dtgCafeAgent =
        MailboxProcessor.Start
            (fun inbox ->
                let rec messageLoop () =
                    async {
                        let! msg = inbox.Receive()

                        match msg with
                        | OrderDrink (drink, amount) ->
                            let drinkPrice : float = getPrice drink
                            let mutable totalPrice = ((drinkPrice: float) * (amount: float))

                            if drink.type' = Coffee then
                                totalPrice <- dgtVAT totalPrice VAT

                            printfn
                                "Please pay DKK%d for your %d %A %A drinks. %s!"
                                (Convert.ToInt32(totalPrice))
                                (Convert.ToInt32(amount))
                                (string drink.type')
                                (string drink.size)
                                "Thanks!"
                        | LeaveAComment (comment) -> printf "Comment: %A" comment

                        return! messageLoop ()
                    }

                messageLoop ())

    member this.Order msg = dtgCafeAgent.Post msg


When I send the messages to the agent, it is printing stuff in a very messed way.当我将消息发送给代理时,它正在以非常混乱的方式打印内容。

let bar = Bar()
let testDrink = { type' = Coffee; size = Small }

bar.Order(OrderDrink({ type' = Coffee; size = Small }, 2.0))

let orderDrinks =
    [ (OrderDrink({ type' = Coffee; size = Small }, 1.0))
      (OrderDrink({ type' = Coffee; size = Medium }, 2.0))
      (OrderDrink({ type' = Juice; size = Small }, 3.0))
      (OrderDrink({ type' = Soda; size = Medium }, 4.0))
      (OrderDrink({ type' = Milk; size = Large }, 5.0)) ]

orderDrinks |> List.map (fun o -> bar.Order o)

// output
> orderDrinks |> List.map (fun o -> bar.Order o);;
valPlease pay DKK24 for your 1  "Coffee" "Small" drinks. Thanks!!
it Please pay DKK72 for your 2 "Coffee" :"Medium" drinks. Thanks!!
 unitPlease pay DKK 45 for your 3 list"Juice" "Small" drinks. Thanks!!
 =Please pay DKK51 for your 4  "Soda" "Medium" drinks. Thanks!!
[()Please pay DKK;125 for your 5 "Milk"  "Large" drinks. Thanks!!
(); (); (); ()]

As I see, it should print every statement as written in the code.如我所见,它应该打印代码中编写的每条语句。

Fsi is evaluating your expression. Fsi 正在评估您的表情。 Since bar.Order() returns unit, the result of your expression is [();由于 bar.Order() 返回单位,因此表达式的结果是 [(); (); (); (); (); (); (); ()]. ()]。 So Fsi wants to print something like所以 Fsi 想要打印类似的东西

val it : unit list = [(); (); (); (); ()]

Meanwhile, the mailbox processor is on another thread working through its queue, printing messages as it does so.同时,邮箱处理器在另一个线程上处理它的队列,同时打印消息。 The two threads are both sending text to the same output, ie they are stepping on each other.两个线程都在向同一个 output 发送文本,即它们相互踩踏。

Just do做就是了

orderDrinks |> List.iter bar.Order

if you just want to print the results.如果您只想打印结果。

List.map would instead convert the output, but the output is of type unit eg () and get you the garbled result you see. List.map 将改为转换 output,但 output 是单元类型,例如 () 并得到你看到的乱码结果。

Edit: you also need to start fsi quiet so it doesn't print variable evaluations eg fsi --quiet编辑:您还需要启动 fsi quiet 所以它不会打印变量评估,例如 fsi --quiet

Otherwise the behaviour is correct since it shows how the mailbox processor starts executing tasks, and hands over control to the caller before it finishes.否则行为是正确的,因为它显示了邮箱处理器如何开始执行任务,并在完成之前将控制权移交给调用者。 Thus the caller fsi, starts printing val it: unit ().因此调用者 fsi 开始打印 val it: unit ()。 At the same time that the mailbox processor is working.同时邮箱处理器正在工作。 Both processes writing to the console at the same time, producing garbled output.两个进程同时写入控制台,产生乱码 output。

Still List.Iter is used when you are executing functions that have no output eg have unit () output;当您执行没有 output 的函数时仍然使用 List.Iter,例如有单元 () output; which will in turn return only one unit () output rather than one unit () per each list item.这反过来将只返回一个单位 () output 而不是每个列表项一个单位 ()。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM