core-async

2019-12-18T08:32:01.146400Z

Just nitpicking a bit regarding the above, channel operations in a thread are blocking the thread instead of parking. They have different names so you can’t confuse them (<!! instead of <!). Also, an async/thread isn’t exactly normal. It’s a daemon thread so you can’t rely on the JVM to wait for it at the end of the program.

kwrooijen 2019-12-18T08:47:22.146500Z

Yeah true, I find it a bit cumbersome to write go block because of the macro expansion. But that’s a whole different topic

kwrooijen 2019-12-18T08:48:34.146700Z

Do you have any good resources about something like “concurrency theory”. Because I hear daemon thread, JVM thread, native thread, POSIX thread. But I wouldn’t be able to explain the differences

dharrigan 2019-12-18T09:12:06.146900Z

What would the shape of that look like, i.e., to use a go block, spawn a thread and wait for the data to be emitted back into the go block for processing (if I've understood that correctly)?

kwrooijen 2019-12-18T09:31:42.147100Z

(go
  ;; ... Do whatever
  (let [result (&lt;! (thread-call query-data))]
    ;; ... Do something with `result`
    ))
Something like this I guess?

2019-12-18T09:34:47.147300Z

That’s an example of a one-off thread. A thread might also continuously produce data into a channel, which you can read in a go-loop.

dharrigan 2019-12-18T09:44:25.147500Z

(go-loop [result (&lt;! (thread-call query-data))]
    ;; ... Do something with `result`)

dharrigan 2019-12-18T09:44:27.147700Z

?

roklenarcic 2019-12-18T09:45:20.147900Z

why would you use go blocks if you are using full threads anyway?

roklenarcic 2019-12-18T09:47:24.148700Z

at that point you might as well use futures and a threadpool

roklenarcic 2019-12-18T09:48:14.149200Z

I don’t know why you’d want to create a new thread instead of using cached thread pool

kwrooijen 2019-12-18T09:51:02.149300Z

Maybe you have multiple go block in your architecture, but 1 of them needs to do IO. That would make sense to me at least

kwrooijen 2019-12-18T09:52:20.149500Z

On the other hand maybe that’s not how you build concurrent systems in Clojure. I’ve only written them in Erlang so I’m trying to switch my mindset

roklenarcic 2019-12-18T09:53:13.149700Z

it depends on your IO boundaries’ implementation

roklenarcic 2019-12-18T09:53:49.149900Z

if you’re using a standard synchronous implementation then you need to have a thread pool that handles that IO

roklenarcic 2019-12-18T09:54:19.150100Z

what you do elsewhere is up to you

roklenarcic 2019-12-18T09:54:46.150300Z

you can stuff the result of IO threads into channels and use go blocks to process that

roklenarcic 2019-12-18T09:55:37.150500Z

or you can simply pass IO thread a callback function, that it executes with the results, that function is executed on IO thread then, but if it’s short its not a problem

roklenarcic 2019-12-18T09:56:09.150700Z

and generally you have a threadpool on inbound IO anyway (web server has its own threadpool which processes request handlers)

roklenarcic 2019-12-18T09:57:05.150900Z

so if you’re not careful, even if you use go block, you might end up blocking on the result of that go block, which means you await on request thread for result anyway

roklenarcic 2019-12-18T09:58:32.151100Z

so to have a fully aync solution you need to have async inbound IO, so a webserver that gives you a callback to call with the results or a webserver that will take a channel as response

dharrigan 2019-12-18T10:36:32.151300Z

Very useful information!

jumar 2019-12-18T11:18:11.151500Z

@kevin.van.rooijen "Java Concurrency in Practice" by Brian Goetz is a good on

kwrooijen 2019-12-18T11:26:10.151700Z

Thanks!

fmjrey 2019-12-18T12:30:31.151900Z

Great discussion indeed, very timely in my case too. Overall, async/thread makes a lot of sense for long running processes (i.e. daemons) such as IO. For these you do not want to take a thread from a bounded pool (such as clojure.core/future which uses the agent pool). And since async/thread creates daemon threads, you need to either take from the channel it returns within a non-daemon thread, or have an entirely separate control mechanism, so that the JVM does not exit before your processing is done. Is that a fair summary?

fmjrey 2019-12-18T12:44:54.153800Z

Unless you really need long running daemon threads, e.g. to consume from kafka and put messages into a channel

fmjrey 2019-12-18T12:50:19.154900Z

For databases a typical scenario is a connection pool with its own thread pool

kwrooijen 2019-12-18T12:50:40.155100Z

Yeah, that’s what I was thinking

kwrooijen 2019-12-18T12:50:58.155500Z

But I’m also reading that certain websocket libraries use core async to handle connections

kwrooijen 2019-12-18T12:51:41.156200Z

If that’s true, wouldn’t it make sense to query a thread pool from a go block?

kwrooijen 2019-12-18T12:53:10.157Z

I also think that @roklenarcic and I had a bit of a miscommunication, because my intention is to use a thread pool. I was just using an example

fmjrey 2019-12-18T12:53:57.157300Z

websockets.... clojure side or clojurescript side?

kwrooijen 2019-12-18T12:55:06.157700Z

Both

kwrooijen 2019-12-18T12:55:10.158Z

But I could be mistaken

fmjrey 2019-12-18T12:55:15.158100Z

on cljs side there are no threads...

kwrooijen 2019-12-18T12:55:30.158400Z

There is, one at least 😛

kwrooijen 2019-12-18T12:55:44.158800Z

I haven’t looked into it in detail so I can’t really comment

kwrooijen 2019-12-18T12:56:24.159100Z

But I’m mainly talking about the Clojure side

roklenarcic 2019-12-18T13:01:27.159200Z

IO are not daemons

fmjrey 2019-12-18T13:02:09.160100Z

If you are listening to something yes, e.g. kafka consumer

roklenarcic 2019-12-18T13:02:40.160700Z

I see that people are confused. Daemon threads in Java are just threads that do not prevent JVM from exiting when running.

roklenarcic 2019-12-18T13:03:19.161400Z

JVM will exit when all non-daemon threads stop

fmjrey 2019-12-18T13:03:30.161500Z

Or a web server waiting for new connections and handing off requests to your code

roklenarcic 2019-12-18T13:03:50.161700Z

those threads are explicitly NOT daemon

roklenarcic 2019-12-18T13:04:03.161900Z

otherwise JVM would exit while waiting for requests

fmjrey 2019-12-18T13:04:24.162100Z

hence my earlier comment

roklenarcic 2019-12-18T13:04:44.162300Z

Usually the main function starts the server (a threadpool of non-daemon threads) that wait for requests

roklenarcic 2019-12-18T13:05:06.162500Z

and main function then exits

roklenarcic 2019-12-18T13:05:13.162700Z

if threads were daemon then JVM would exit too

kwrooijen 2019-12-18T13:06:17.163200Z

Ah, that’s a good distinction to know