Comparing F# Queues

There are some useful additions to the F# tool-belt coming up. Microsoft recently released a preview edition of immutable collections, and if all goes as planned I will release a suite of 6 purely functional linear data structures to FSharpx.Collections in just a couple of days.

Queue is a data structure that needs better representation in the functional world, and both collections make contributions, so this is an opportunity to do some performance comparisons of the queues available to F# programmers. The contenders are two queues from the .NET Framework, System.Collections.Generic.Queue and System.Collections.Concurrent.Queue, the upcoming FSharpx.Collections.Queue, and FSharpx.Datastructures.BatchedQueue, from which FSharpx.Collections.Queue was developed.

The first benchmark exercises something like “real world” usage of the queues with the following steps:

1) enqueue the number of elements indicated

2) peek and dequeue half that number

3) enqueue the same number to the resulting queue

4) peek and dequeue half the resulting size of that queue

5) enqueue one more time the original number

(Milliseconds on a 2.2GHz 4GB dual core 64-bit Windows 7 machine)

  102 103 104 105 106
sys.queue 0.8 0.8 1.2 5.2 45.7
sys.concurrentqueue 1.9 2.1 2.8 10.9 90.3
sys.immutablequeue 1.4 1.5 2.7 21.2 401.4
fsharpx.queue 1.5 1.6 2.7 20.8 404.3
fsharpx.batchedqueue 2.0 2.2 4.0 32.8 n/a

And then the obligatory “not so real world” benchmarks

Enqueue the indicated number of elements

  102 103 104 105 106
sys.queue 0.3 0.3 0.4 1.1 8.8
sys.concurrentqueue 0.4 0.5 0.6 1.7 12.8
sys.immutablequeue 0.5 0.5 0.8 4.0 91.6
fsharpx.queue 1.1 1.2 1.4 3.7 102.4
fsharpx.batchedqueue 1.2 1.2 1.5 7.8 n/a

Peek and Dequeue until the queue is empty

  102 103 104 105 106
sys.queue 0.2 0.2 0.2 0.7 6.2
sys.concurrentqueue 0.7 0.7 0.8 2.4 18.9
sys.immutablequeue 0.5 0.5 0.7 3.3 74.7
fsharpx.queue 0.6 0.6 0.7 1.3 26.8
fsharpx.batchedqueue 0.7 0.7 0.9 1.8 n/a

Initialize from a sequential source (an array unless otherwise indicated)

(The preview Immutable.Queue does not yet implement this capability.)

  102 103 104 105 106
sys.queue 0.3 0.3 0.4 1.2 9.6
sys.concurrentqueue 0.3 0.3 0.3 0.9 6.6
fsharpx.queue ofList 0.1 0.1 0.1 0.1 0.1
fsharpx.queue 0.7 0.7 0.7 1.2 13.1
fsharpx.batchedqueue 0.8 0.8 0.8 1.3 n/a

Use IEnumerable to iterate through each element

(queue of indicated size)

  102 103 104 105 106
sys.queue 0.1 0.1 0.2 0.7 6.9
sys.concurrentqueue 0.7 0.7 0.8 1.3 7.0
sys.immutablequeue 0.7 0.7 0.9 2.4 55.8
fsharpx.queue 2.1 2.1 2.4 4.7 27.6
fsharpx.batchedqueue 2.1 2.2 2.4 4.7 n/a

So which Queue is right for You?

That of course depends on your application. For raw speed the system generic queue is hard to beat. The concurrent queue compares well against generic in all categories in a single-threaded environment, so for raw speed it should be a contender in multi-threaded environments, unless composability and immutability is preferred.

Preview Immutable.Queue seems primarily intended for the C# world, but has adequate composability to make it suitable for F#. FSharpx.Collections.Queue performs just as well (sometimes better), and has a broader range of supporting functions including fold, foldback, reverse (usually O(1), worst case O(n)), ofSeq, and ofList.

2 thoughts on “Comparing F# Queues

  1. Pingback: F# Weekly #3, 2013 « Sergey Tihon's Blog

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>