core-async

Ben Sless 2020-05-15T08:17:46.209300Z

Reading Hoare's paper, I notice core.async doesn't provide exactly the same semantics as the alternative command. What are your thoughts on this implementation as a general idea? I'm focusing here on emulating the semantics, not performance

cavan 2020-05-15T13:25:30.213400Z

Hello, i came across a bug recently with core.async's timeout channel, In my web-server i create a timeout channel for each request and close it at the end of the request.. the problem is the timeout channel sometimes are created with the time-period already expired during high load... I know this has been reported before in the past (https://clojure.atlassian.net/browse/ASYNC-225) and the obvious explanation i saw was to not close the timeout channel and let the Garbage collection handle it for you. But that causes a LOT of memory usage.. so i'm not sure what is the best way ahead. Ideas will be much appreciated. Thanks guys in advance

2020-05-15T15:31:37.214400Z

You must not close timeout channels

➕ 2
2020-05-15T15:35:45.218400Z

It is best to consider timeout channels as a global resource. Your memory usage issues are likely because mutiple requests are getting the same timeout channel, and when you close a timeout channel for 1 request you are incorrectly also closing the timeout for other requests

2020-05-15T15:36:15.219100Z

So those other requests are prematurely cleaning up

cavan 2020-05-15T16:22:42.224Z

Thank you for replying, Yes i agree 100% that is what is happening, but as i mentioned i create a new timeout channel each time a http request is made AND on the server runs where i don't close channels explicitly, i just end up with a lot of CPU/ram usage(which is probably because i create many channels and the GC is slow to collect the ones that are obsolete, leaving behind a lot of stuff in memory), which goes away with closing channels... but closing channels brings woes of its own as you've mentioned.. As a hack i thought to replicate the timeout channel by creating a new channel, and doing a sleep on it for the same time as the timeout would be and then dropping something on the said channel to signify timeout is complete... but that doesn't look too pretty and i was hoping you guys had some better alternatives 🙂

ghadi 2020-05-15T16:28:40.224700Z

closing a channel doesn't usually release resources anyways

ghadi 2020-05-15T16:30:11.225900Z

I'm not clear on what the objective is

cavan 2020-05-15T17:02:27.229500Z

sorry if i was unclear, But the gist of it is to be able to create a lot of new timeout channels for each http request.. (i find myself closing timeoutchannels at the end because if i don't, i see a significant increase in CPU use.).. But by closing timeout channels, i sometimes run into the problem where the new timeout channel i create is actually an older channel that is already exhausted.. I want each timeout channel to be a new resource so i'm not bitten by that behaviour... i searched around and see that this problem has been documented in the past https://clojure.atlassian.net/browse/ASYNC-225

2020-05-15T17:05:31.230200Z

this is an intentional behavior of core.async - by reusing / duplicating them it reduces overhead, by closing them you prevent other people from getting their timeouts

2020-05-15T17:06:41.230700Z

notice the issue tag on the issue you linked was literally edited from "bug" to "new feature"

cavan 2020-05-15T17:08:51.231400Z

Yes i did notice it , and was hoping if someone experienced this issue before and had a workaround for it 🙂

2020-05-15T17:15:04.233Z

I'd take a closer look at what's using the CPU -- it could be that you were reducing load by dropping events on the floor, but that only adresses the symptom - maybe you need larger units of work between channel ops, maybe you need to move CPU intensive tasks out of go blocks into threads

2020-05-15T17:16:03.233600Z

and IO usage out of go blocks as well

2020-05-15T17:16:34.233800Z

you may just have a bit of a space leak

❤️ 1
2020-05-15T17:16:57.234300Z

because the timeout is shared between requests it causes the callbacks on the channel to persist between requests

2020-05-15T17:17:21.234800Z

so introducing some level of indirection between the timeout and the callbacks may help

2020-05-15T17:18:56.236Z

(defn my-timeout [ms] (async/go (async/<! (async/timeout ms))))

2020-05-15T17:21:46.238100Z

having high cpu usage without closing timeout channels sounds like a bug somewhere though

cavan 2020-05-15T17:24:19.238800Z

I loved the idea about having the indirection, not sure how succesful it would be , but i'm definitely gonna try it , thanks! 😄

ghadi 2020-05-15T17:45:10.239700Z

closing a channel is very different than closing an InputStream

ghadi 2020-05-15T17:45:32.240300Z

there's no file descriptors or heavyweight things that are relinquished

dpsutton 2020-05-15T17:56:10.241Z

> new timeout channel i create is actually an older channel that is already exhausted.. I want each timeout channel to be a new resource so i'm not bitten by that behaviour. this sentence seems weird to me. an exhausted timeout channel. does this mean already elapsed?

2020-05-15T17:59:27.241900Z

what closing a channel tends to release is anyone waiting on the channel, which can be callbacks that close over just about anything

2020-05-15T18:00:09.242600Z

likely the timeout channel isn't closed (exchausted) because the timeout is elapsed in this scenario it is likely closed because some other request already closed it

cavan 2020-05-15T18:21:39.243500Z

yes i meant elapsed, sorry for the confusion

cavan 2020-05-15T18:22:49.243700Z

sorry for the confusion, by exhausted i mean elapsed. Since i create timeout channels for each request, at times i would come across newly created timeout channels that are already elapsed since i believe timeouts are shared in cljs.core.async