Live data from Hacker News

Notes on structured concurrency, or: Go statement considered harmful

vorpus.org

201–210 of 234 posts

Re: Notes on structured concurrency, or: Go statement considered harmful

#201
post #8

Earlier quoted context omitted.

> * Does anything else like this currently exist (other than the Trio library he mentions), which shows that it's a superior paradigm in practice? Erlang's supervisor behaviours are basically that. They add some more stuff (the actual supervision) but fundamentally every process in a supervision tree will necessarily manage and outlive all its children processes.

Sure, but Erlang solves this problem indirectly. There's no risk of concurrent processes unexpectedly changing state (the real problem Trio addresses, or at least reduces the blast radius of) because there is no shared state.

> Sure, but Erlang solves this problem indirectly.

It solves the issue quite directly.

> There's no risk of concurrent processes unexpectedly changing state (the real problem Trio addresses, or at least reduces the blast radius of) because there is no shared state.

That doesn't seem to have any relevance to Trio's purpose, a low-level spawn has this exact same guarantee and yet is pointed to as a problematic primitive right in the introduction. The essay says literally nothing about unexpected state changes. In fact the word "state" appears nowhere in the essay. The essay is about control flows and their structuring (or lack thereof).

Re: Notes on structured concurrency, or: Go statement considered harmful

#202

It's amazing how many people managed to skim through the post, and hammer on their own preconceptions and facile counter-arguments, for things that are all addressed in the argument. And that's for a very well written post, that tries to address all common issues. And yet, people manage to get it wrong, or write facile responses like "re-implementing the fork/join". Not to mention missing the whole nuance of what the…

If the author knows about Rust, it's a little odd that he didn't mention scoped-threadpool, which is pretty close to this idea:

http://kimundi.github.io/scoped-threadpool-rs/scoped_threadp...

EDIT: He compares to Rust in a comment on the Reddit thread:

https://www.reddit.com/r/programming/comments/8es8x3/notes_o...

As an aside, HN users tend to sneer at Reddit, but this is another case where the discussion on Reddit is better than the one here.

Re: Notes on structured concurrency, or: Go statement considered harmful

#203

The author appears to have reinvented Communicating Sequential Processes (CSP). http://www.usingcsp.com/cspbook.pdf The (simplified, and as I understand it) gist of concurrency in CSP is that the program is expressed as a series of parallel (PAR) and sequential (SEQ) operations. Everything in a PAR block will run in parallel and all their outputs will be collected and fed as the input to the next SEQ. Everything in a…

It's not immediately clear whether or not the reified nursery object breaks this correspondance.

I think it does, which seem to make it quite interesting.

Re: Notes on structured concurrency, or: Go statement considered harmful

#204
I found this pretty fascinating and I'm looking forward to hearing the theoreticians chew it over.

A question I had was with the API that's been chosen. The `nursery` is chosen as the reified object, and a function `start_soon` is exposed on it. Perhaps in other parts of the library there are other methods exposed on `nursery`? If not, in some languages it seems like the `start_soon` method itself would make more sense as the thing to expose. In use, it might do like this:

    ...
    nusery {
      (go) in
      go { this_runs_concurrently_in_the_nursery }
      go { this_also_runs_concurrently_in_nursery }
      // make a regular function call passing it the nursery's `go`
      some_func(go)
    }
    ...
And elsewhere:

    ...
    func some_func(go) {
      do_something()
      go {
        nursery {
          // This nursery is within the outer one.
          (go2) in
          go2 { do_stuff }
          go2 { do_more_stuff }
        }
      }
    }
    ...

Re: Notes on structured concurrency, or: Go statement considered harmful

#205

Earlier quoted context omitted.

Nurseries and lifetimes are orthogonal concepts. In fact, Rust already has a "nursery", except it's generally called a scoped threadpool. They use lifetimes to ensure the threads can reference stuff on the stack without copying it. So a "nursery" is basically just a scoped threadpool with a 'static lifetime.

I don’t think there’s any reason a nursery has to have a static lifetime.

I would definitely consider the "nursery" to be a newly created device (threadpool/reactor/...), where the resources used by the functions run in this "nursery" only has a lifetime requirement equal to the nursery.

Re: Notes on structured concurrency, or: Go statement considered harmful

#206
Is incredible how easy is to miss the point of this.

Let me try with something else.

Imagine you have try/catch/finally BUT NOT AS CONTROL FLOW CONSTRUCS but "just api calls".

So, you language need to be used like:

    foo()
    exceptions.try{
    	bar()
    	this.catch{
    	
    	}
    }
It means, you need to remember to ALWAYS REMEBER to "close" the start of the call.

Imagine how bad this could be. If only "try/catch" was as with "IF/ELSE/ENDIF" so you not do something stupid like:

    foo()
    exceptions.catch{
    	what?()
    }
    bar()

Re: Notes on structured concurrency, or: Go statement considered harmful

#207
post #74

I found it an interesting idea and writeup. It'd be good to see what could be done in a language that implemented this - concurrency only allowed in the context of nurseries. On the downside, though, I think there's a lot of concurrency patterns that could only be implemented by creating a nursery near the top level of the application and passing it around all over the place, thus getting you pretty much right back w…

> I think there's a lot of concurrency patterns that could only be implemented by creating a nursery near the top level

Yes, the same thing is true of goto and other control flow patterns. Patterns change to match the tools available.

Re: Notes on structured concurrency, or: Go statement considered harmful

#208

Earlier quoted context omitted.

> That is 100% possible with goroutines. It really isn't. The big difference is that "goto" can lead to code you read being grossly misunderstood due to complicated flows, potentially even absurd things like jumping to a different function. (And as you mention, good code can be written with goto's—it can make particularly error handlers much easier to read in C.) This is not the case at all with "go", which is extrem…

> I must disagree that asynchronous programming increase the complexity of writing good code Could you say more about why? It seems to me that purely synchronous code is much easier to reason about than async code, in that a) less is happening at once, and b) things happen linearly. That seems less complex almost by definition. I'd certainly believe that things like goroutines are better than the threading that came…

> But I can't see how it's less complex than linear code.

I am being misinterpreted here (in a peculiar way that has happened before on HN...). I wrote that it does not increase the complexity "in any measurable fashion".

It seems that you interpreted this as "concurrency is less complex than non-concurrency", when in reality I am saying "concurrency is a tiny bit more complex than non-concurrency" (extra emphasis on "tiny").

Now, back to the topic:

Asynchronous programming is strictly speaking the simple idea that code will be run later when some conditions are met. For example, running a callback when a network response is received from the "fetch" API in modern JS, with all I/O handled behind the scenes by an event engine of sorts.

I do not believe that this concept provides any measurable increase in cognitive load. You only concern yourself with these devices where they are used, and they are extremely simple to wrap your head around.

In another model, you may have full parallelism and shared memory access, in which case you need to be more careful to only use thread safe structures. Even then, unless you do something stupid™, everything is fine, and the cognitive load is increased globally but only mildly so with a model similar to goroutines and channels.

Finally, you may have to design and use synchronized/atomic data structures, in which case things increase in difficulty. While this does increase cognitive load in a small area of the code, I does not increase the cognitive load over the entire application. However, just like not all application need to design a cryptographic protocol, not all applications need to design concurrent data structures even if it uses concurrency. Thus, one should additionally note that this localized overhead is not a universal overhead of all concurrent programming.

BTW, I do not find that goroutines present less cognitive load than pthreads ("threading") and a CSP library. They simply present syntactic sugar for a better developer experience. They also give an M:N threading implementation unlike pthreads, but that's an implementation detail.

Re: Notes on structured concurrency, or: Go statement considered harmful

#209

Earlier quoted context omitted.

> while “go” is clear when read… I believe our industry’s several decades of demonstrated inability to write concurrent code correctly disagrees with you. Languages like go (and Rust, to a greater degree) have improved the situation. But there are still a ton of sharp edges that existing approaches still have, and—often—they’re ones that aren’t readily apparent until after a project starts growing and begins unearthi…

> I believe our industry’s several decades of demonstrated inability to write concurrent code correctly disagrees with you. Not at all. Concurrent/parallel code isn't particularly difficult to write—there's just a unique class of problems related to it that might occur, but that does not mean it is hard . Rather, the industry has through several decades demonstrated an inability to write bug free code in general. I w…

I guess we can debate what "hard" means, but I think "adds a lot more problems that are much harder to reason about and avoid" is exactly the definition of hard. If it's not, I'm honestly not sure what is. Torn reads, deadlocks, concurrent modification, the effects on optimizers, the overhead of scheduling and lock management. Each of these are deep, complicated issues you only have to deal with when writing concurrent (well, parallel) code.

But yeah I mean, if you mean it's pretty easy to call pthread_create then OK. But if you at all care about your program working, then parallel code is much, much harder to write.

Re: Notes on structured concurrency, or: Go statement considered harmful

#210

Earlier quoted context omitted.

Nothing could describe this post (or anything on the author’s site in general) less accurately than your comment.

How so?

Because the author engages directly with the core point Dijkstra made, and proposes a new abstraction which parallels with that core point. The author does so in a clear and thoughtful way which cannot be dismissed out-of-hand.
Post reply on HN