Well, you pay a cost whenever you use seqs instead of reduce, so it/s 
strange to think of doseq as "as fast as possible". If it/s argument is a 
true collection, its IReduce is usually faster than its seq. If it is a 
sequence already, its IReduce is usually just using seqs anyway.

Let's get some rough numbers here (which is what you should do on a 
case-by-case basis):

(require  '[uncomplicate.fluokitten.core :as f])
=> nil
(def side-effect (constantly nil))
=> #'user/side-effect
(def col1 (range 10000))
=> #'user/col1
(def col2 (range 10000))
=> #'user/col2
(def col2 (vec (range 10000)))
=> #'user/col2
(def col1 (vec (range 10000)))
=> #'user/col1

Single-coll:

(time (dotimes [_ 10] (doseq [x col1] (side-effect x))))
"Elapsed time: 13.916077 msecs"
=> nil
(time (dotimes [_ 10] (dorun (map side-effect col1))))
"Elapsed time: 5.707441 msecs"
=> nil
(time (dotimes [_ 10] (run! side-effect col1)))
"Elapsed time: 1.190621 msecs"
=> nil


Notice there seems to be some overhead to doseq that dorun doesn't have, so 
actually map+dorun is faster (for this particular coll). And run! is the 
fastest because a vector's IReduce is significantly faster than its seq.

Multi-coll:

(time (dorun (map side-effect col1 col2)))
"Elapsed time: 13.194375 msecs"
=> nil
(time (run! side-effect (map vector col1 col2)))
"Elapsed time: 17.54224 msecs"
=> nil
(time (run! side-effect (mapv vector col1 col2)))
"Elapsed time: 3.892984 msecs"
=> nil
(time (f/foldmap f/op nil side-effect col1 col2))
"Elapsed time: 12.454673 msecs"
=> nil
(time (dorun (sequence (map side-effect) col1 col2)))
"Elapsed time: 31.321698 msecs"
=> nil

Interesting results.

So dorun+map is still pretty good. foldmap wins out a little bit, but is 
still clearly using seqs underneath.

run! over a seq is not better than just consuming the seq. This is because 
the IReduce of a seq uses first/next internally, so there is no IReduce win.

However, run! over a vector is faster (for this collection, at this size) *even 
though we are creating a bunch more intermediate collections!*. The IReduce 
of a vector is really *that much faster* than its seq! So if you really 
need speed and don't care about laziness or memory, it may be faster just 
to make the intermediate collections-of-collections and reduce over it. 
Benchmark your particular hotspot!

And even though sequence uses iterators internally, there is clearly still 
some extra overhead involved.


On Friday, September 23, 2016 at 10:58:42 PM UTC-5, Mars0i wrote:
>
> Thanks very much Francis.  
>
> So it sounds as if, if my data would already be in a vector, list or 
> sequence (maybe a lazy sequence), doseq will process that structure as fast 
> as possible, but there are other structures that might have faster internal 
> reduce operations.
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to