2009/10/19 Christophe Grand <christo...@cgrand.net>

> Hi,
>
> On Mon, Oct 19, 2009 at 7:59 AM, harto 
> <stuart.william.campb...@gmail.com>wrote:
>
>> I've just started learning Clojure, so I'm trying to figure out the
>> correct way of doing things. I've been trying to create and 'modify' a
>> large vector for an online programming exercise, but I'm running into
>> some performance issues.
>>
>> Any general tips would be appreciated!
>>
>> Firstly, I'm creating a vector of booleans like this:
>>
>> (defn vector-of [n value]
>>  (vec (for [_ (range n)] value)))
>>
>> It takes quite a long time for large values of n, though:
>>
>> user=> (time (dorun (vector-of 1e7 true)))
>> "Elapsed time: 6734.509528 msecs"
>>
>
> You don't need dorun here: dorun is sometimes used in benchmarks to force
> the computation of lazy-seqs but here you are using a vector, not a lazy
> seq. So calling dorun on it causes the allocation of a seq of 1e7 items
> which takes time. If you used dorun to prevent the printing of the vector at
> the REPL, just di (tcime (count (vector-of 1e7 true))). See:
> user=> (time (dorun (vector-of 1e7 nil)))
> "Elapsed time: 4155.616985 msecs"
> nil
> user=> (time (count (vector-of 1e7 nil)))
> "Elapsed time: 2384.609217 msecs"
> 10000000
>

OK, thanks. I thought I'd need dorun to get a true benchmark because I was
using those intermediate lazy sequences. But, it looks like I was misusing
those anyway :)


>
> If you study your function:
> (defn vector-of [n value]
>  (vec (for [_ (range n)] value)))
>
> You'll see that to create a vector of n items you use two intermediate seqs
> of size n items (range and the result of for).
> If you get rid of some allocations, you'll get huge speed-ups.
>
> (defn vector-of [n value]
>   (loop [n (int n) v []]
>     (if (zero? n)
>       v
>       (recur (dec n) (conj v value)))))
>
> user=> (time (count (vector-of 1e7 nil)))
> "Elapsed time: 1170.371793 msecs"
> 10000000
>
> Since you don't care about intermediate values of v, you can use
> transients:
> (defn vector-of [n value]
>   (loop [n (int n) v (transient [])]
>     (if (zero? n)
>       (persistent! v)
>       (recur (dec n) (conj! v value)))))
>
> user=> (time (count (vector-of 1e7 nil)))
> "Elapsed time: 228.272239 msecs"
> 10000000
>
>
>
>> Secondly, I'm iterating across one of these large vectors using
>> something like the following (contrived) function:
>>
>> (defn set-flags [v]
>>  (loop [i 0
>>         v v]
>>    (if (< i (count v))
>>        (recur (inc i) (assoc v i false))
>>        v)))
>>
>> user=> (let [v (vector-of 1e7 true)] (time (dorun (set-flags v))))
>> "Elapsed time: 15563.916114 msecs"
>>
>>
> For reference (using my fastest vector-of):
> user=> (let [v (vector-of 1e7 true)] (time (count (set-flags v))))
> "Elapsed time: 5653.562953 msecs"
> 10000000
>
> Here too you don't care about intermediate values of v:
> (defn set-flags [v]
>  (loop [i 0 v (transient v)]
>    (if (< i (count v))
>        (recur (inc i) (assoc! v i false))
>        (persistent! v))))
>
> user=> (let [v (vector-of 1e7 true)] (time (count (set-flags v))))
> "Elapsed time: 1423.473584 msecs"
> 10000000
>
> And if you store (count n) in a local:
> (defn set-flags [v]
>   (let [n (count v)]
>     (loop [i 0 v (transient v)]
>       (if (< i n)
>        (recur (inc i) (assoc! v i false))
>        (persistent! v)))))
>
> user=> (let [v (vector-of 1e7 true)] (time (count (set-flags v))))
> "Elapsed time: 931.911668 msecs"
> 10000000
>

Thanks very much. I wasn't aware of transients until reading this. In fact,
I had to search the Clojure website to find the relevant page (
http://clojure.org/transients).

Cheers!


>
> hth,
>
> Christophe
>
>
>
> --
> Professional: http://cgrand.net/ (fr)
> On Clojure: http://clj-me.blogspot.com/ (en)
>
>
> >
>

--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to