This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-06-12
Channels
- # aleph (1)
- # aws (2)
- # babashka (44)
- # beginners (178)
- # biff (12)
- # calva (22)
- # chlorine-clover (60)
- # cider (1)
- # clj-kondo (9)
- # cljdoc (6)
- # cljs-dev (37)
- # cljss (2)
- # clojure (43)
- # clojure-europe (3)
- # clojure-finland (23)
- # clojure-italy (1)
- # clojure-nl (4)
- # clojure-norway (3)
- # clojure-spec (56)
- # clojure-uk (148)
- # clojuredesign-podcast (1)
- # clojurescript (11)
- # conjure (5)
- # core-async (22)
- # cursive (9)
- # datascript (5)
- # datomic (4)
- # duct (8)
- # emotion-cljs (2)
- # figwheel-main (15)
- # fulcro (53)
- # graalvm (68)
- # helix (2)
- # jackdaw (1)
- # kaocha (9)
- # lambdaisland (1)
- # malli (10)
- # meander (2)
- # news-and-articles (1)
- # observability (12)
- # off-topic (17)
- # pathom (1)
- # pedestal (25)
- # practicalli (1)
- # protojure (4)
- # re-frame (2)
- # reagent (57)
- # reitit (1)
- # releases (2)
- # shadow-cljs (69)
- # specter (6)
- # tools-deps (10)
- # vim (16)
- # vscode (4)
- # yada (3)
Happy Friday š
I could get quite excited about Java Project Loom simplifying parallel processing, enabling us to do away with Fork/Join and reducers
but I have no idea when it is supposed to land
does anybody know?
morning
I've had to do some simple analytic stuff in node/typescript lately, and I gotta say, we're spoiled in clojureland with laziness and the various collection apis
@ben.hammond probably a few years
@ben.hammond: Yeah not sure thereās a concrete release date for it yetā¦ IIRC itās currently built on JDK15 which is due for release in sept 2020ā¦ so JDK16 at the earliestā¦ but I think 17 or 18 is more realistic. Iām hoping for 17 because thatās also an LTS release.
i knew there was a good reason why I hate getting excited
Yeahā¦
> I can deal with the despair... > its the hope...
Iām curious why you think itāll do away with ForkJoin/reducers thoughā¦ I was thinking itād be better for replacing the underpinnings of core.async
I would expect everying to be a plain old thread
no need for Tasks
no need for weird coroutine type structures
cljs is a compelling reason yes
well we shouldnāt break core.async for sureā¦ but !>>
rather than !>
could possibly be built ontop of virtual threads; which wouldnāt affect cljs at all.
I was looking into loom a few weeks ago. A colleague had mentioned how he was hoping itād mean we could finally create an efficient CML implementation in clojure and on the JVM.
So Iād been looking into that and have started playing a little with CML, which is essentially core.async++++
Still trying to get my head around it though Aside from this I think the main thing Iām looking forward to in project loom is that it finally means you can do blocking I/O in a scalable way. Iāve found NIO based systems, e.g. pedestal to be a bit of a PITA when youāre dependent on dozens of parsers that were all totally reasonably written with blocking IO in mind. You then need to start pooling access to them or risk blocking all your threads.
Concurrent ML
ML as in 'Standard ML'?
CML was essentially an ML like language implemented to do concurrencyā¦ there was a follow on implementation called manticore that rebuilt it for true parallelism: http://manticore.cs.uchicago.edu/
but as far as I can tell the most popular implementations of it are all in scheme
Racketās standard lib has what appears to be a faithful CML implementationā¦ though frustratingly they donāt cite it as such.
Also guile has one
and I think there are versions of Haskell that have it
star haskell or something
Thereās an attempt at an implementation of it on top of core.async too: https://github.com/polytypic/poc.cml But it seems core.async isnāt quite good enough to do it justice.
This is what is most commonly cited as the important work for understanding it: https://www.amazon.co.uk/Concurrent-Programming-ML-John-Reppy/dp/0521480892
it looks like CML doesn't have much to do with ML apart from ML having been the incubation language ?
yeah thatās my impression
itās really just a concurrency/parallelism abstraction
well i've got some new things on my reading list now š
I must admit right now I donāt really understand what makes it so greatā¦ At a superficial kind of level it seems similar to core.async. What I will say is people in the know, seem to cite as being state of the art and superior to everything elseā¦ Iāve not heard anyone say this, but it feels a bit like the blub paradox for concurrencyā¦ I donāt understand what Iām missing; but some smug CML weenies might be onto something š
its all about projecting confidence
... probably
I get the feeling that thereās more to it than that ā¦. probably š
There is this YT talk on the subject: https://youtu.be/pf4VbP5q3P0 Which attempts a comparison to other things, amongst others core.async ā however I donāt think he does a particularly good job of explaining all his points.
is the CML runtime written in C? is it compatible with anything else
seems kind of hard to imagine doing real work in an isolated ecosystem nowadays
perhaps I've been plugged in to the JVM multiverse for too long
Itās an academic language as far as I can tell
So they probably only want it to be adopted for their research.
i too have difficulty imagining working in anything which didn't have a similarly rich ecosystem to the JVM @ben.hammond
"I later designed a concurrent ML implementation for an obscure language called star, which you can still find if you look for it"
reminds me of
"In 1966, I went down to Greenwich Village, New York City to a rock club called the Electric Banana. Don't look for it, it's not there anymore."
something about the way the presenter said that made me chuckle out loud
I'm about half way through that vid, and while interesting, the word 'monad' keeps appearing like an intrusive thought
AH I get it, they're synchronous, which is why they compose
yep I'm being dumb
or am I
selective communication is just (conditional) logic
monads are just computation, as are take ops in core async
so is it about non determinism then? hm
yes it's about ordering of in & out okay
ah so you can reason about it at the point that channels converge and diverge
okay I think that's the Big Idea... is it? the rendez-vous
right and that a go block is only for composing inputs and it's not that efficient and under the hood it's a continuation
ok and selective communication is just a mechanism for communicating with multiple partners and that's what alts are
yeah thanks to @rickmoynihan for posting the info, p interesting
@alex.lynham the rendezvous aspect exists elsewhere and I think predates CML, e.g. the CSP literature which core async / go are based around.
As far as I can gather CML reifies events in a way core.async and others donāt; and importantly CML supports NAKs which lets a process decide itās no longer available for rendezvous.
Monadās I think are only relevant in that you can transform code from do
notation into CPS via a continuation monad; which is one way to implement green threadsā¦ the go
macro being another.
CML also has guards and a few other concepts; which I think make it easy to efficiently implement other concurrency systems in terms of CML; but the reverse is allegedly seldom true.
sounds like rendezvous might be from a lang called occam(?)
but yeah by monads, I kinda meant that interaction point, as represented by a go block - was thinking out loud really... seemed like maybe the same sort of thing, heh
either way, v interesting
@alex.lynham the m-word was coming up for me too, because it's a compositional framework so the : rv f -> rv
operation used for wrap
is bind
, choose
looks like an fmap
etc... choose
/ select
are quite interesting - it took me a moment to realise that they are roughly interrogating the backpressure state and select different execution paths based on which channel will permit a put/take (as opposed to doing starting multiple concurrent operations and selecting the first available result)
Are there any nice event driven libs that people can recommend that are cljc? The only thing coming to mind is re-frame
, but I think itās only cljc to aid in testingā¦
The other thing Iām thinking of is hand rolling something using core.async?
Iām thinking of writing a small proof of concept version my sim to be event driven. See if it allows me to increase comprehension of whatās going on in the code, improve performance, potentially batching events which are similar to improve cache locality. Right now it runs on a time-step and is more ECS style.
re-frame's fundamental model is very simple @folcon... reduce a stream of events onto a state object using a set of registered event handler fns. if you leave the interceptors and fx out it's almost trivial
Depending on what you're doing, an agent/atom can be seen as an event handler pattern.
When you say Iām right to do what Iām doing, you mean the proof of concept? Or that my current ECS model is fine as it is? I also have a suspicion that the reactive/subscription system will let me do nice caching etcā¦
@folcon I don't know what your ECS model is :) I just mean that skipping re-frame might be a good choice.
Ah, you're after a reactive programming system with caching. Got it :) I'd say building that on core.async is iffy.
Broader context is the simulation is the base level of the game Iām working on =)ā¦ So stuff runs on a ātickā, any new player actions are queued for next tick evaluation, so between ticks I want to evaluate the current world as well as player actions from prior ticks. Itās a game, so I expect logic to get complicated fast and Iām trying to figure out good ways to keep complexity down but keep performance evaluation up
So parallelism in the context of similar player actions and entities in the sim need to be computed to work out what effects they have, then apply those effects to the worldā¦
Well Iām not certain what the best approach is here, Iāve looked at: 1) Writing updates as I go 2) Keeping the prior world state and collecting updates, then apply them all at the end The second approach is cleaner, but slowā¦
Do you essentially want parallelism to allow concurrent modifications of state where those pieces of state don't affect each other?
That's because it's not useful in a lot of contexts. Most applications are (mostly) stateless. But your whole program is about modelling state.
Hmm, Iām getting the feeling that thereās not going to be much documentation to do this then?
Documentation? Plenty. There's loads on http://clojure.org about it's state constructs. Examples? Nah.
I think the ants demo should be plenty though ^ State is really simple in Clojure :)
@folcon I'm not super experienced with refs or anything, but I'd be happy to help you debug any ? you end up with. I'd like to help improve my understanding.
The other thing Iām worried about is reproducibility, am I going to get issues that are going to be impossible to debug by opening the non-determinism doorā¦
If you're doing concurrency then you give up event ordering & perfect reproducibility. It's on you to make sure your state changes fit within the rules of the world. For example if pieces can be frozen, then any "moves" from that point onward should factor that in (or not, your game, your rules!)
Iām currently writing up a blog post that covers some of the system Iāve built alreadyā¦ which is much simpler than what weāre discussing, but I feel like this is an area that Iāve not seen much (read any) tutorials in and I would like to see more sim-agent based games being written =)ā¦
I think Clojure would make a good game-logic language, especially given that games take ages to start anyway.
but I donāt believe that I need to persist it while itās running? Instead I was thinking of async persisting it while itās running. IE: Compute a tick, save the output while broadcasting it to the clientsā¦ I did a bunch of experiments trying to work out how to do the kinds of operations I wanted to do in the db level, but it always turned out quite slowā¦
Well I was just trying to think of what needs to be loaded, ie the server reboots and youāll need to pickup the game state =)ā¦
Yea thereās a fun question of how much working memory some of this stuff takes, thatās the downside of my async idea :)ā¦
Btw, are there any good resources around working in transducers that are a bit more complex that just flat collections? Been trying to figure out if how Iām reducing this is efficient
(defn update-category [pantry-category portions-required]
(-> (reduce-kv
(fn [{:keys [portions-to-eat] :as state} food-name {:keys [portions] :as food-detail}]
(if (<= portions-to-eat portions)
(reduced (-> state
(update-in [:pantry-cat food-name :portions] - portions-to-eat)
(assoc :portions-to-eat 0)))
(-> state
(update :pantry-cat dissoc food-name)
(update :portions-to-eat - portions))))
{:pantry-cat pantry-category
:portions-to-eat portions-required}
pantry-category)
:pantry-cat))
(defn amount-to-eat [pantry day-of-food]
(reduce-kv (fn [pantry food-category portions-required]
(cond-> pantry
(contains? pantry food-category)
(update food-category update-category portions-required)))
pantry day-of-food))
(let [day-of-food {:food-base 18, :food-extra 18, :drink-base 18}
pantry {:food-extra {"Eggs" {:name "Eggs",
:category :food-extra,
:portions 168}},
:food-base {"Hard Bread" {:name "Hard Bread",
:category :food-base,
:portions 126}},
:drink-base {"Cheap Beer" {:name "Cheap Beer",
:category :drink-base,
:portions 156}}}]
(eat-from-pantry pantry day-of-food))
Not certain pantry is the best structure as is, but I wrote it that way to make sure that items are stackableā¦This is interesting:
Loading src/ants.clj... done
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by clojure.lang.InjectedInvoker/0x0000000800b8ac40 (file:/Users/folcon/.m2/repository/org/clojure/clojure/1.10.1/clojure-1.10.1.jar) to method sun.java2d.SunGraphics2D.drawImage(java.awt.Image,int,int,java.awt.image.ImageObserver)
WARNING: Please consider reporting this to the maintainers of clojure.lang.InjectedInvoker/0x0000000800b8ac40
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Reducers are generally very fast. You're usually looking at algorithmic complexity in your code.
Hmm, ok, I was asking because I saw some stuff in cgrandās xforms, but couldnāt quite work out how to use them =)ā¦ Might have to rethink this structure thenā¦
Transducers are faster than lazy sequences. Reducers and transducers have comparable performance.
@dominicm So digging into this ant demo a little, were you thinking of the āagentsā as a sort of threadpool which bounces back and forth between game entities? Or modelling each agent in the same way as an ant? Iām asking Iām not certain how many āantsā I can run at once? My design calls for a lot of independent agents, but I wasnāt thinking of them all as running simultaneously (mostly because I wasnāt sure that was possible =)ā¦), instead I was thinking of them as computing their action and then moving onto the next oneā¦
@folcon each entity in your game as a ref, like in the ants demo. My understanding is that it scales very well.
Hmm, itās really not liking 10000 ants =)ā¦
[258.039s][warning][os,thread] Failed to start thread - pthread_create failed (EAGAIN) for attributes: stacksize: 1024k, guardsize: 4k, detached.
Hmm, itās probably the Thread sleep here:
(. Thread (sleep ant-sleep-ms))
If I increase the world size from 80 to 180, I also start getting pausesā¦