Fork me on GitHub
#core-async
<
2018-01-15
>
ajs20:01:22

inside a go block, what is the difference between putting onto another channel via put! vs >!. i've always used put even from inside go blocks

noisesmith20:01:57

put! has no backpressure - it returns immediately and leaves your go block running

noisesmith20:01:27

while >! will pause that block until the value is consumed or buffered, which means you have backpressure

ajs20:01:38

i see, >! is synchronous, put! is async

noisesmith20:01:56

both are async - when you pause the go block you are pausing a state machine and it resumes later

noisesmith20:01:19

but yeah - it’s kind of like that

noisesmith20:01:36

but it’s an important distinciton in cljs for example, that both are properly async

ajs20:01:36

i suppose put! is fine unless for some reason I need to access the value from another channel within the same go block?

noisesmith20:01:03

put! works for simple things, as your design evolves having backpressure will prevent a lot of problems

ajs20:01:39

i'm trying to think of a reason why i'd need to care about backpressure in a go block

ajs20:01:49

maybe all i do is simple stuff 😉

noisesmith20:01:53

I would only use put! inside a go block if I need to consume from the same channel I just sent to, later in the same block

noisesmith20:01:31

@ajs in the jvm, there’s only a small number of threads to run go blocks on, and it’s easy to get them congested

noisesmith20:01:48

in cljs it’s even worse - only one thread shared by both core.async and all other code

ajs20:01:15

i mainly use cljs only

noisesmith20:01:23

when you use put! you don’t cause the context switch that lets other code (eg. the code that needs that value) to run

noisesmith20:01:35

so in cljs put! can cause deadlocks that >! would not cause

noisesmith20:01:46

(at least in theory)

ajs20:01:50

you said, >! will pause that block until the value is consumed or buffered -- doesn't that mean the execution will possibly continue after this put even if it is not actually consumed and dealt with (in the case it is bufferred), in which case if you depend on it being consumed it would be no different than a put! ?

noisesmith20:01:20

the distinction is that put! doesn’t introduce a context switch

noisesmith20:01:40

which means that the other code isn’t given a chance to run

ajs20:01:11

so if your go block is doing something, and it depends on some other go block or take operation happening before your go block is done, you'd want >!

noisesmith20:01:54

or if you need any other go block or non go block code to run, period, you need to eventually call <!, >!, or exit

ajs20:01:17

well i use put! and <! exclusively but have wondered why I don't use >!

ajs20:01:39

i guess i don't understand the context switch you are talking about, or why i'd care when putting onto a channel if it is consumed right away

noisesmith20:01:45

another aspect here is that put! is not part of the CSP model

noisesmith20:01:06

it doesn’t get consumed if you never let the context switch

noisesmith20:01:22

(unless you count “being buffered for use” as consumption)

ajs20:01:51

perhaps you can use a different term than context switch, that's not clarifying for me

noisesmith20:01:54

your code works because eventually you either exit or use <! - but if you started using take! as well for example, you could easily lock up your app

noisesmith20:01:32

js is cooperative multitasking - there’s nothing inside your code (except eg. setTimeout?) that can interrupt your code mid execution

noisesmith20:01:02

<! and >! are yields in the coroutine model, they inform the go system that other code is free to run

noisesmith20:01:25

with coroutines, it’s good policy to yield whenever it makes sense to

ajs20:01:02

outside a go block, the only way to put onto a channel asynchronously is with put! if you don't want to block, so perhaps i just got into that habit and therefore did that in go blocks too

ajs20:01:22

though I guess the question is why putting outside a go block needs to be asynchronous

noisesmith20:01:31

that’s a reasonable explanation. But I’d default to >! in go blocks unless there’s a pressing reason not to

noisesmith20:01:58

same reason: it needs to be async because there’s no preemption so your code blocks for ever, nothing can create the condition that would allow it to continue

ajs20:01:37

so in short, recommended to put! outside a go block, >! instead inside a go block, and always take with <! in a go block

noisesmith20:01:40

when you have one thread and no preemption, waiting on a condition is equivalent to a deadlock

ajs20:01:09

i'll refactor a few puts and see what happens

ajs21:01:42

here's another theoretical. in js, what if any performance difference would you find between sending things around to say 10 different channels, which are read from in 10 go blocks, vs. (if your logic allowed for this), having a "heterogeneous" single channel that would accept 10 different responsibilities and handle different types of message content accordingly

noisesmith21:01:36

I wonder - sounds like an interesting thing to try measuring

ajs21:01:12

i'd expect possibly less memory by having less state machines around, but that's probably trivial