This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-05-01
Channels
- # announcements (2)
- # babashka (26)
- # beginners (26)
- # biff (18)
- # boulder-clojurians (2)
- # cider (16)
- # clj-kondo (34)
- # cljs-dev (4)
- # clojure (22)
- # clojure-denver (10)
- # clojure-europe (16)
- # clojure-nl (1)
- # clojure-norway (10)
- # clojure-uk (2)
- # clojurescript (25)
- # conjure (3)
- # cursive (11)
- # datomic (11)
- # dev-tooling (6)
- # emacs (6)
- # etaoin (7)
- # events (1)
- # fulcro (6)
- # humbleui (11)
- # hyperfiddle (15)
- # instaparse (2)
- # introduce-yourself (2)
- # jobs-discuss (1)
- # lsp (26)
- # malli (7)
- # reitit (5)
- # releases (1)
- # sci (6)
- # shadow-cljs (16)
- # specter (5)
- # vim (5)
Related to the above:
Let’s say I have a fn read-char
which I know returns a java char
. Since this is a protocol fn, the Clojure compiler boxes this and read-char
is typed to return an Object
. What would be the fastest way to compare the output of read-char
to a known char, eg \"
? I’ve been playing with:
1. (= \" (char (read-char s)))
2. (= 32 (int (read-char s)))
3. (= \" (read-char s))
Looking at the output from the compiler, it seems to me that 2 should be faster, since we then get emitted =
whereas the two others use various versions of Util.equiv
to do the comparison.
I’m sure it’s not sufficient to just look at the decompiled bytecode, since there will probs be some jit stuff involved as well
have you tried criterium quick-benchmark on those?
I’ve been playing a little with datafy+nav. It feels a little like an ERM. Is using it in production code to navigate model relationships a usage that people have opinions on? I’d be curious if people would advise for or against.
It’s intended for any situation where you need to treat as data something that may be an object graph, so definitely is not a “dev” tool only
Hey team, noob concurrency question for you.
I want to create a cache, with two usage scenarios:
1. Given a cache at time T
, find all K
that needs be invalidated, and invalidate them
2. Given a K
, lookup-or-miss: either find it, or update the cache with the result for K
Now the problem, what would be the best kind of concurrency primitive to wrap this cache in?
I could go with the handy atom
. This would support 1.
Really well. I could easily get a "current view" of the cache at time T
, to find all the keys I want to invalidate
But, I wonder about 2
. If I use an atom, all writes to the cache would contend with each other. It's clear to me that different K
's are not related to eachother, so the contention here is a bit unnecessary.
I noticed the recommendation for clojure.core.cache
is to use atom though. Is the contention on writes not really a big deal? How would you think about it?
what would be the concern for the contention for writes? the compare and set semantics in an atom should have the desired effect i think?
My thinking is the compare-and-set in the atom would re-run "unnecessarily". if lookup-or-miss runs for two different K
, they could conflict, but my thought was "do they really need too?"
yeah atoms are uncoordinated so some unnecessary iterations are expected. the way i understand is because the swapping fn is pure its "fine". works out well in real life
I would say: try clojure.core.cache.wrapped
(which wraps the clojure.core.cached
API in an atom automatically) and see how performance is for you.
We use c.c.c.w
extensively at work for a lot of stuff and haven't had performance problems so far...
In reality, it will depend on your usage patterns and what sort of cache invalidation strategy you need. It sounds like you're after TTL which is built-in for c.c.c.w and it already handles (most of) the tricky edge cases with invalidation on access for you.
(making a bullet-proof cache is hard enough that I wouldn't recommend trying to write one yourself when a Contrib lib already exists for this)
I'll look deeper into c.c.c.w and see about using it. My usecase is a bit esoteric (I invalidate by listening to Postgers' write-ahead log), but there's lots I can leverage for this in c.c.c.w
i think this approach is interesting and i’d like to investigate it more: https://github.com/cnuernber/ham-fisted/blob/master/src/ham_fisted/api.clj#L1121
Also check out https://github.com/ptaoussanis/encore/blob/master/src/taoensso/encore.cljc#L2557, which makes clever use of https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java + delays as values. Fwiw I think that contention on write is typically not worth worrying about, and if it becomes so, sticking write transactions in a single queue and batch applying them from one thread can get you pretty far.
When I invoke a clojure alias, using clj -M. should I be doing clj -M:foo or clj -Mfoo. both seem to do the same thing
Aliases begin with :
so -M:foo
is correct. Don't rely on -Mfoo
continuing to work.
thanks!