Fork me on GitHub
#architecture
<
2021-07-11
>
Zaymon02:07:43

Thanks for the interesting responses everyone. Follow up, a lot of what I am seeing here in the discussion is related to perf and scaling. Has anyone found that the model for core.async encourages good system design? It seems to me one of the biggest benefits would be the easy de-coupling of subsystems, and effects (although I’m not sure if it’s worth it for a small project over regular sync function calls). The ability to easily de-couple producer and consumer (for example req -produces> command -consumes> command handlers -produces> effects) seems like a win, but I’m interested if anyone has any thoughts on this in practice 🙂. Side note, this community has been the most thoughtful and welcoming I’ve come across and I’m stoked to be here.

emccue02:07:26

Queues in general are the way to decouple things

emccue02:07:04

java's queues fit this purpose just as well for separating larger systems

3
emccue02:07:50

I don't think the more "micro" uses of chan - i.e. alts, as essentially promises - are necessarily the same kind of decoupling

phronmophobic02:07:04

I primarily think of clojure.core.async as a library that helps reason about programs that have multiple, independent, logical processes that must coordinate. compared to promises, futures, deferreds, j.u.concurrent, I find it easier to write correct programs that have lots of moving parts. In addition to the bounded queues, clojure.core.async offers alts! which doesn't have a counterpart in many of the other options.

11
phronmophobic02:07:00

I also think having a strong theoretical basis (http://usingcsp.com/cspbook.pdf) really starts to show when you do have to implement a problem that is inherently very complex and correctness is important.

👀 3
phronmophobic02:07:39

Some other architectural honorable mentions to look out for when evaluating libraries that target concurrency: • are there parking/non parking versions for each operation? • is there a story for handling back pressure?

4
potetm03:07:11

Another thing to keep in mind: Yes decoupling when something happens from where it happens is nice when you can afford it. Often, things need to be done now and in order. Tacking a bunch of queues in the middle of that sort of process will add significant complexity for little gain.

2
hiredman18:07:30

almost all modern webservers are an argument against that. handling an http request is something that happens "now and in order" so a traditional fork a thread per request would seem to make sense, but I think every high performance webserver written post this paper (https://people.eecs.berkeley.edu/~brewer/papers/SEDA-sosp.pdf) has stuck a bunch of queues in the middle of that

hiredman19:07:39

http://matt-welsh.blogspot.com/2010/07/retrospective-on-seda.html is a retrospective on the paper by an author a decade after the paper

potetm20:07:28

Yeah, I mean. If you pull out the stopwatch and profiler and really dig into it, there are gains to be had.

potetm20:07:42

But he pretty much summarizes my view in his retrospective: > I would only put a separate thread pool and queue in front of a group of stages that have long latency or nondeterministic runtime, such as performing disk I/O. But even with that, it’s fair to say that manually managing a queue adds a lot of complexity compared to having a reified stack (a la Loom).

potetm20:07:54

(As an abstraction. It’s fine to have asynchrony and queues in an implementation if you still offer a stack.)

potetm20:07:07

Anyways, the advice was geared towards people who want to make a good-enough decision for run-of-the-mill application code. Manually tracking a synchronous request across multiple queues is a massive conceptual pain. I wasn’t trying to say there are zero gains for doing so.