Fork me on GitHub
#clojure-uk
<
2020-06-12
>
dharrigan07:06:07

Good Morning!

Jakob Durstberger07:06:44

Happy Friday šŸ™‚

Ben Hammond07:06:20

I could get quite excited about Java Project Loom simplifying parallel processing, enabling us to do away with Fork/Join and reducers

Ben Hammond07:06:53

but I have no idea when it is supposed to land

Ben Hammond07:06:58

does anybody know?

alexlynham07:06:07

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

dominicm07:06:55

@ben.hammond probably a few years

rickmoynihan08:06:34

@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.

Ben Hammond08:06:10

i knew there was a good reason why I hate getting excited

Ben Hammond08:06:40

> I can deal with the despair... > its the hope...

rickmoynihan08:06:57

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

Ben Hammond08:06:23

I would expect everying to be a plain old thread

Ben Hammond08:06:29

no need for Tasks

Ben Hammond08:06:15

no need for weird coroutine type structures

dominicm08:06:26

core.async should stay as it is, no? It's great because it works in cljs too.

Ben Hammond08:06:47

cljs is a compelling reason yes

rickmoynihan08:06:34

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.

rickmoynihan08:06:31

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.

rickmoynihan08:06:18

So Iā€™d been looking into that and have started playing a little with CML, which is essentially core.async++++

rickmoynihan08:06:47

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.

Ben Hammond08:06:45

ML as in 'Standard ML'?

rickmoynihan08:06:32

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/

rickmoynihan08:06:49

but as far as I can tell the most popular implementations of it are all in scheme

rickmoynihan08:06:33

Racketā€™s standard lib has what appears to be a faithful CML implementationā€¦ though frustratingly they donā€™t cite it as such.

rickmoynihan08:06:49

Also guile has one

rickmoynihan08:06:01

and I think there are versions of Haskell that have it

rickmoynihan08:06:11

star haskell or something

rickmoynihan08:06:22

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.

rickmoynihan08:06:14

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

mccraigmccraig08:06:30

it looks like CML doesn't have much to do with ML apart from ML having been the incubation language ?

rickmoynihan08:06:46

yeah thatā€™s my impression

rickmoynihan08:06:13

itā€™s really just a concurrency/parallelism abstraction

mccraigmccraig08:06:29

well i've got some new things on my reading list now šŸ˜ƒ

rickmoynihan08:06:34

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 šŸ™‚

dominicm08:06:36

Report back when you figure it out

Ben Hammond08:06:33

its all about projecting confidence

rickmoynihan08:06:11

I get the feeling that thereā€™s more to it than that ā€¦. probably šŸ™‚

rickmoynihan08:06:45

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.

Ben Hammond08:06:14

is the CML runtime written in C? is it compatible with anything else

Ben Hammond08:06:48

seems kind of hard to imagine doing real work in an isolated ecosystem nowadays

Ben Hammond08:06:14

perhaps I've been plugged in to the JVM multiverse for too long

rickmoynihan08:06:26

Itā€™s an academic language as far as I can tell

rickmoynihan08:06:58

So they probably only want it to be adopted for their research.

mccraigmccraig09:06:08

i too have difficulty imagining working in anything which didn't have a similarly rich ecosystem to the JVM @ben.hammond

maleghast09:06:55

Morning All!

maleghast09:06:49

Anyone know if there is a newer hotness for shelling out than Conch..?

alexlynham09:06:39

"I later designed a concurrent ML implementation for an obscure language called star, which you can still find if you look for it"

alexlynham09:06:43

reminds me of

alexlynham09:06:54

"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."

alexlynham09:06:18

something about the way the presenter said that made me chuckle out loud

alexlynham09:06:32

I'm about half way through that vid, and while interesting, the word 'monad' keeps appearing like an intrusive thought

alexlynham09:06:32

AH I get it, they're synchronous, which is why they compose

alexlynham10:06:48

yep I'm being dumb

alexlynham10:06:23

selective communication is just (conditional) logic

alexlynham10:06:27

monads are just computation, as are take ops in core async

alexlynham10:06:25

so is it about non determinism then? hm

alexlynham10:06:49

yes it's about ordering of in & out okay

alexlynham10:06:42

ah so you can reason about it at the point that channels converge and diverge

alexlynham10:06:59

okay I think that's the Big Idea... is it? the rendez-vous

alexlynham10:06:18

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

alexlynham10:06:05

ok and selective communication is just a mechanism for communicating with multiple partners and that's what alts are

folcon12:06:35

Mornā€™ =)ā€¦

folcon12:06:32

Ohh, not heard of CML, new stuff to look over when I have a moment =)ā€¦

alexlynham13:06:15

yeah thanks to @rickmoynihan for posting the info, p interesting

rickmoynihan13:06:17

@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.

alexlynham13:06:11

sounds like rendezvous might be from a lang called occam(?)

alexlynham13:06:06

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

alexlynham13:06:15

either way, v interesting

mccraigmccraig16:06:20

@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 fmapetc... 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)

folcon17:06:17

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?

dominicm17:06:34

@folcon depends what properties you want from your events.

dominicm17:06:05

For my event use cases, "hand rolling" core.async is only a few lines.

folcon17:06:38

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.

mccraigmccraig20:06:44

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

dominicm20:06:06

and the wonky stuff with request animation frame

folcon20:06:07

True, just wasnā€™t sure if itā€™s going to do some odd stuff within the jvmā€¦

dominicm20:06:16

fwiw, I think you're right to do what you're doing

dominicm20:06:50

Depending on what you're doing, an agent/atom can be seen as an event handler pattern.

folcon20:06:27

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ā€¦

dominicm20:06:24

@folcon I don't know what your ECS model is :) I just mean that skipping re-frame might be a good choice.

folcon20:06:43

Ah ok =)ā€¦

dominicm20:06:49

Ah, you're after a reactive programming system with caching. Got it :) I'd say building that on core.async is iffy.

dominicm20:06:02

I doubt you're going to get parallelism anyway, especially with re-frame.

dominicm20:06:09

I'd personally consider using an agent.

dominicm20:06:18

(Dunno your broader context though)

folcon20:06:26

Hmm, is that something Iā€™m going to have to handroll?

dominicm20:06:43

@folcon what paralellism are you looking for exactly?

folcon20:06:14

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

folcon20:06:44

Itā€™s designed to run in a server with player actions coming over websocketsā€¦

folcon20:06:54

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ā€¦

Wes Hall21:06:08

@folcon What transaction isolation do you need for all this? šŸ˜‰

folcon21:06:09

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ā€¦

dominicm21:06:01

this sounds perfect for Clojure's STM to meā€¦

dominicm21:06:36

Do you essentially want parallelism to allow concurrent modifications of state where those pieces of state don't affect each other?

folcon21:06:42

In what way?

dominicm21:06:50

I guess not then :p

dominicm21:06:31

Sorry, I said 2 things and got mixed up :)

dominicm21:06:35

It's getting late.

dominicm21:06:51

@folcon have you seen Rich's ants demo?

folcon21:06:26

I have, but not really used any of those constructs =)ā€¦

dominicm21:06:40

I think they're a perfect fit for what you're describing.

folcon21:06:49

Iā€™ve seen the core.async demo and talk in clojurescript =)ā€¦

folcon21:06:36

Iā€™ve just never seen sync etc used in code in the wild?

dominicm21:06:20

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.

folcon21:06:33

Hmm, Iā€™m getting the feeling that thereā€™s not going to be much documentation to do this then?

dominicm21:06:36

Documentation? Plenty. There's loads on http://clojure.org about it's state constructs. Examples? Nah.

dominicm21:06:01

I think the ants demo should be plenty though ^ State is really simple in Clojure :)

dominicm21:06:15

@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.

folcon21:06:21

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ā€¦

folcon21:06:36

Well that would be good =)ā€¦

dominicm21:06:22

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!)

folcon21:06:23

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 =)ā€¦

dominicm21:06:53

I think Clojure would make a good game-logic language, especially given that games take ages to start anyway.

folcon21:06:16

True, but I also need to ensure that doesnā€™t create inconsistency =)ā€¦

Wes Hall21:06:07

@folcon Do you need to persist this state?

folcon21:06:07

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ā€¦

dominicm21:06:53

round-tripping to the db will be slow, I like your async idea :)

folcon21:06:10

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 =)ā€¦

folcon21:06:27

Yea thereā€™s a fun question of how much working memory some of this stuff takes, thatā€™s the downside of my async idea :)ā€¦

folcon21:06:56

Looks like I need to dig into the ant demo =)ā€¦

folcon22:06:59

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ā€¦

folcon22:06:39

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

dominicm22:06:30

Transducers are only for "flat sequences" (they're an abstraction of conj)

dominicm22:06:47

Reducers are generally very fast. You're usually looking at algorithmic complexity in your code.

folcon22:06:44

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ā€¦

folcon22:06:46

My shopping/eating simulation is just eating up a bit too much time >_<ā€¦

dominicm22:06:04

I'm lying a little bit, but I'm basically telling you the truth :)

dominicm22:06:32

Transducers are faster than lazy sequences. Reducers and transducers have comparable performance.

folcon22:06:38

I see šŸ˜ƒ

folcon23:06:48

@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ā€¦

dominicm23:06:48

@folcon each entity in your game as a ref, like in the ants demo. My understanding is that it scales very well.

folcon23:06:23

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ā€¦