Thursday, July 19, 2012

Speeding up F# Printf.*

There recently was an interesting SO question on F# Printf.* family of functions:

http://stackoverflow.com/questions/11559440/how-to-manage-debug-printing-in-f

It is known that these functions are very slow. Slow enough for most people to avoid them entirely, despite the advantages they offer in verifying argument types.

What I did not know is that these functions are so slow that a few lines of simple user code can speed them up, without changing the interface:

open System.Collections.Generic
type Cache<'T> private () =
static let d = Dictionary<string,'T>()
static member Format(format: Printf.StringFormat<'T>) : 'T =
let key = format.Value
match d.TryGetValue(key) with
| true, r -> r
| _ ->
let r = sprintf format
d.Add(key, r)
r
let sprintf' fmt =
Cache<_>.Format(fmt)
#time
for i in 1 .. 10000 do
ignore (sprintf "%i" 15)
for i in 1 .. 10000 do
ignore (sprintf' "%i" 15)
view raw Sprintf.fs hosted with ❤ by GitHub


With this code I get from 2x to 10x speedups. It is suspicous, I am afraid F# does not cache parsing of the format strings. There is no reason why it should not.

Exercise for the reader: fix the code above to be thread-safe.