type Message<'a> =
  | Enqueue of 'a
  | Dequeue of (seq<'a> -> unit)

while true do
  do
    let n = 1000000
    let agent =
      MailboxProcessor.Start(fun inbox ->
        let msgs = Array.zeroCreate n
        let i = ref 0
        let rec loop() =
          async { let! msg = inbox.Receive()
                  match msg with
                  | Enqueue x ->
                      msgs.[!i] <- x
                      incr i
                      return! loop()
                  | Dequeue reply ->
                      reply msgs }
        loop())
    let timer = System.Diagnostics.Stopwatch.StartNew()
    for i=1 to n do
      agent.Post(Enqueue i)
    agent.PostAndReply(fun reply -> Dequeue reply.Reply)
    |> ignore
    printfn "%f msgs/s" (float n / timer.Elapsed.TotalSeconds)

  do
    let n = 1000000
    let queue = ResizeArray()
    use barrier = new System.Threading.Barrier(2)
    System.Threading.Thread(fun () ->
      let msgs = Array.zeroCreate n
      let i = ref 0
      let rec loop() =
        let xs = lock queue (fun () -> let xs = queue.ToArray() in queue.Clear(); xs)
        let rec iter j =
          if j = xs.Length then loop() else
            match xs.[j] with
            | Enqueue x ->
                msgs.[!i] <- x
                incr i
                iter (j+1)
            | Dequeue reply ->
                reply msgs
                barrier.SignalAndWait()
        iter 0
      loop()).Start()
    let timer = System.Diagnostics.Stopwatch.StartNew()
    for i=1 to n do
      lock queue (fun () -> queue.Add(Enqueue i))
    let msgs = ref Seq.empty
    lock queue (fun () -> queue.Add(Dequeue(fun xs -> msgs := xs)))
    barrier.SignalAndWait()
    let t = timer.Elapsed.TotalSeconds
    printfn "%f msgs/s" (float(Seq.length !msgs) / t)