clojurefunctional-programmingreducetransducer

Why is my transducer function slower than using ->> operator?


While solving problem from Hackkerank (https://www.hackerrank.com/challenges/string-compression/problem) I've written 2 implementations with and without transducers.

I was expecting the transducer implementation to be faster, than the function chaining operator ->>. Unfortunately, according to my mini-benchmark the chaining operator was outperforming the transducer by 2.5 times.

I was thinking, that I should use transducers wherever possible. Or didn't I understand the concept of transducers correctly?

Time:

"Elapsed time: 0.844459 msecs"

"Elapsed time: 2.697836 msecs"

Code:

(defn string-compression-2
  [s]
  (->> s
       (partition-by identity)
       (mapcat #(if (> (count %) 1)
               (list (first %) (count %))
               (list (first %))))
       (apply str)))

(def xform-str-compr
  (comp (partition-by identity)
        (mapcat #(if (> (count %) 1)
                (list (first %) (count %))
                (list (first %))))))

(defn string-compression-3
  [s]
  (transduce xform-str-compr str s))

(time (string-compression-2 "aaabccdddd"))
(time (string-compression-3 "aaabccdddd"))

Solution

  • The transducer version does seem to be faster, according to Criterium:

    (crit/quick-bench (string-compression-2 "aaabccdddd"))
                 Execution time mean : 6.150477 µs
        Execution time std-deviation : 246.740784 ns
       Execution time lower quantile : 5.769961 µs ( 2.5%)
       Execution time upper quantile : 6.398563 µs (97.5%)
                       Overhead used : 1.620718 ns
    
    (crit/quick-bench (string-compression-3 "aaabccdddd"))
                 Execution time mean : 2.533919 µs
        Execution time std-deviation : 157.594154 ns
       Execution time lower quantile : 2.341610 µs ( 2.5%)
       Execution time upper quantile : 2.704182 µs (97.5%)
                   Overhead used : 1.620718 ns
    

    As coredump commented, a sample size of one is not enough to say whether one approach is generally faster than the other.