Live data from Hacker News

Notes on structured concurrency, or: Go statement considered harmful

vorpus.org

31–40 of 234 posts

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

#31
post #30

I'm really growing fond of the async/await abstraction. How do I get this in more C-like languages like Go, Rust, or C++? (I have a bunch of C++ code that I want to call via C ABIs.) I'm intrigued by libdill but it's mysterious enough that I'm scared to include it in my project -- I don't want to risk getting sidetracked by having to debug my concurrency primitives.

In Go you can use waitGroups to ensure that the goroutines are completed, similar to join. You’ll have to pass a cancel chan or context if you’d like to cancel/timeout.

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

#32

This is very very long to explain a very simple pair of ideas: 1) You should be able to declare scoped blocks that mandate execution of all tasks started in that block ends when the scope ends. 2) This is fundamentally superior to all other forms of concurrency. I get it; this is basically what async/await gets you, but conceptually you can spawn parallel tasks inside an awaited block, and know, absolutely that all o…

+1. This is structured programming, applied to concurrent setting. The argument for structured programming was made and won in the '60s [0]. It is amazing that we keep making the same mistakes over and over again.

> The unbridled use of the go to statement has an immediate consequence that it becomes terribly hard to find a meaningful set of coordinates in which to describe the process progress. Usually, people take into account as well the values of some well chosen variables, but this is out of the question because it is relative to the progress that the meaning of these values is to be understood! With the go to statement one can, of course, still describe the progress uniquely by a counter counting the number of actions performed since program start (viz. a kind of normalized clock). The difficulty is that such a coordinate, although unique, is utterly unhelpful. In such a coordinate system it becomes an extremely complicated affair to define all those points of progress where, say, n equals the number of persons in the room minus one!

[0] http://www.u.arizona.edu/~rubinson/copyright_violations/Go_T...

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

#33
post #2

I thought the title was kinda clickbaity, but it turned out to be a great article. Also the comparison to goto really effectively conveyed the point he was trying to make. I have two questions though: * Does anything else like this currently exist (other than the Trio library he mentions), which shows that it's a superior paradigm in practice? * What are the cons to this approach? Why not do it?

Same. I kinda eye-rolled at the title, but got hooked by the article.

I'd be interested in implementing this in Go and throwing a web server implementation at it to see if it makes more sense. Though maybe that's too simple a use-case for it.

It'd be interesting to see how to implement the error propagation using channels, without having any control over the goroutine passed in. If the goroutine panics, how to capture that and pass it back to the nursery?

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

#34
post #30

I'm really growing fond of the async/await abstraction. How do I get this in more C-like languages like Go, Rust, or C++? (I have a bunch of C++ code that I want to call via C ABIs.) I'm intrigued by libdill but it's mysterious enough that I'm scared to include it in my project -- I don't want to risk getting sidetracked by having to debug my concurrency primitives.

Rust is working on exactly this, targeting stabilization later this year: http://aturon.github.io/2018/04/24/async-borrowing/

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

#35
post #22

I LOVE Go's concurrency model, but this article has won me over (pending some experimentation anyway). If you just skimmed, this is actually worth a careful read. The parallels between "go" and "goto" are explained very clearly, and you get some awesome Dijkstra quotes to boot!

I'm not quite won over, but the links to Dijkstra's work were a goldmine for me! Totally agree

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

#36
post #24

Earlier quoted context omitted.

I thought the article's comparison of go routines to goto was fair, in the context made: when calling a function in a language that allows go-routine like things (including pthread_create), one can't know if background tasks will be spawned. This is similar in the free-form time of unrestricted goto that one could not know if control flow really would return to the point lexically after the function call. His propose…

Knowing whether a background task has spawned is very different from not being able to follow the control flow (goto potentially jumping to an entirely different function body). Now, while Go is designed mostly for you to not care about goroutines, there are some corner cases where one must know if a resource is used by anything, such as the chase of when you wish to close a file handle. However, I'd argue that this…

But this concept does also solve that problem. Maybe more simply.

Rust is renowned for being a total headache with borrowing and lifetimes. Nurseries might be a simpler solution for this.

As you say, a corner case. But a common one...

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

#37
I have yet to see any of these problems in core.async (Clojure's version of goroutines). core.async has enabled fantastic programming abstractions like async pipelines using transducers and "socket select" type programming. Perhaps functional programming is the solution to solve concurrency issues.

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

#38

This is usually why I end up using https://godoc.org/golang.org/x/sync/errgroup instead of straight go statements, as it addresses some of the cancellation and error propogation issues. When I think of my use of naked go statements, it's usually for periodic tasks; having something similarly structured for them would be a clear win to me (though potentially the impact is less significant, as it's less painful to writ…

https://godoc.org/github.com/oklog/run is a more-general and IMO more-elegant version of errgroup.

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

#39
post #18
post #3

Earlier quoted context omitted.

I don't think its a superior paradigm, just a different one. I only see his nursery as being useful when you really want your async tasks to complete before the function in which they were dispatched returns. That's far from covering every use case of concurrency! A lot of the value of concurrency is in background operations. These simply can't be tied to the duration of a function call on the dispatch thread. Doing…

> I only see his nursery as being useful when you really want your async tasks to complete before the function in which they were dispatched returns. That's far from covering every use case of concurrency! His section "There is an escape" answers this criticism: "The nursery object also gives us an escape hatch. What if you really do need to write a function that spawns a background task, where the background task ou…

Then what is the difference between the nursery escape and joining a thread or extracting the value of a promise? Both of these will bubble any error back into the dispatch thread.

Seems like we're just layering indirections (I wouldn't call that an abstraction) for little added value over the existing constructs.

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

#40
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 SEQ will run sequentially as a pipeline until the next PAR. Every PAR must follow a SEQ and vice versa, as two PARS or SEQS next to each other will simply coalesce.

eg.

    PAR
      longCall1
      longCall2
      longCall3
    SEQ
      reduceAllThreeResults
      doSomethingWithTheReducedResult
    PAR
      nextParallelOp1
      nextParallelOp2
etc.
Post reply on HN