HackerTrans
TopNewTrendsCommentsPastAskShowJobs

_bsless

no profile record

comments

_bsless
·5 years ago·discuss
Modest proposal - The real problem I see with JSON is it's not rich enough. Not a problem if you're using EDN

https://github.com/edn-format/edn
_bsless
·5 years ago·discuss
*Unless you're paying for the commercial version

Worth noting, GraalVM's JVM implementation has a different JIT compiler which seems to give better performance for highly dynamic and polymorphic languages like Clojure and Scala
_bsless
·5 years ago·discuss
Up to 4 threads I usually see linear scaling as well, but it begins to drop off afterwards, although I don't have a representative example at hand.

I'd like to see a good example if you have one available, most of my performance work was done in a single-threaded context until now
_bsless
·5 years ago·discuss
I don't think there's an immediately available answer here. The wide branch factor in Clojure's implementation is very iteration-friendly, less so for updates.

Worth checking out are BTrees and Hitchhiker trees, but I think a definitive answer will be implementation dependent even in those cases, i.e. one might win out over the other for a specific branch factor or other tune-able parameters
_bsless
·5 years ago·discuss
You could start with these:

https://clojureverse.org/t/parallel-transducing-context-figh...

https://www.reddit.com/r/Clojure/comments/emylbs/any_idea_wh...

https://clojurians.zulipchat.com/#narrow/stream/151168-cloju...

https://github.com/joinr/paralleltest/issues/1

Anything in particular you're looking for?
_bsless
·5 years ago·discuss
Take that with a grain of salt, from experiments run by myself and others I can share this does not scale linearly.

Hope some performance experts can chime in but this might be related to data structure sharing between caches or allocation contention in the JVM.
_bsless
·5 years ago·discuss
That's a fair criticism, but indulge this hypothetical, if you will:

- assume the sliding window transducer existed in the standard library (there's an open jira for it)

- assume the programmer is not an expert, but is familiar with stuff like boxed maths in Clojure, which isn't hard to work around, well documented [1], and has a known performance impact

- assume the programmer will avoid using `last`

- assume the programmer is comfortable using transducers

In short, that the transducer exists and the programmer has at least 6 months of experience programming in Clojure full time.

Will you consider the resulting implementation complicated, in depth or non idiomatic? There's always the possibility I'm just used to it so it comes naturally to me, but as the title suggests, I consider the result, before dropping down to arrays, way more idiomatic than the initial implementation.

I don't begrudge CL's speed and implementation, it's the readiness with which Clojure is dismissed as being slow with only surface familiarity with it.

[1] - https://insideclojure.org/2014/12/15/warn-on-boxed/
_bsless
·5 years ago·discuss
> although he doesn't really explain why HAMTs specifically are slow

Hello, author here :)

HAMTs are certainly slower, for "churning" operations, i.e., lots of updates, which is where Clojure exposes the transient API, which gives you limited localized mutability (some terms and conditions may apply)

Where iteration is concerned, they standard library implementation is pretty good. It relies on chunks of 64 element arrays which store the keys and values contiguously. Thus, APIs which expose direct iteration, Iterator and IReduce(Init) operate on these chunks one at a time. It isn't as fast as primitive arrays, but it's pretty fast.
_bsless
·5 years ago·discuss
Others have made similar comments on comparing apples to oranges when comparing optimized CL to idiomatic Clojure, but what they didn't address was "idiomatic Clojure". Threading a sequence through a bunch of lazy operations is good for development time, but at this point I wouldn't consider it idiomatic for "production" code.

Two things in the implementation are performance killers: Laziness and boxed maths.

- baseline: Taking your original implementation and running it on a sequence or 1e6 elements I generated, I start off at 1.2 seconds.

- Naive transducer: Needs a transducer of a sliding window which doesn't exist in the core yet[0], 470ms

- Throw away function composition, use peek and nth to access the vector: 54ms

- Map & filter -> keep: 49ms

- Vectors -> arrays: 29ms

I'd argue only the last step makes the code slightly less idiomatic. Might even say that aggressively using juxt, partial and apply is less idiomatic than simple lambdas

You can see the implementation here

[0] https://gist.github.com/nornagon/03b85fbc22b3613087f6

[1] https://gist.github.com/bsless/0d9863424a00abbd325327cff1ea0...

Edit: formatting