Live data from Hacker News

Coroutines for Go

research.swtch.com

161–170 of 191 posts

Re: Coroutines for Go

#161

Earlier quoted context omitted.

In practice the difference would be closer to: getNext := iterableThing.Iterator() for { next, ok := getNext() if !ok { break } ... } vs. for next := range iterableThing.Iterator() { ... } One advantage is that it's slightly shorter, which matters for very common patterns--people complain about `err != nil` after all. Another advantage is there isn't another variable for everyone to name differently. Another advantag…

Only newbies tend to complain about `err != nil` in my experience. After a certain point it just clicks and they get used to it. There's a cadence to Go code (do the thing, check the error, do the thing, check the error) that is easy to read once you're used to it, but looks horribly verbose when you're coming from an exceptions-based language. Go has simplicity as a design goal. Part of that simplicity is not adding…

Personally, I don't really see anything wrong with explicit error values, and checking them against nil.

The point I was trying to make is that some amount of people see the benefit in removing much smaller boilerplate. And so presumably at least as many people should see the benefit of removing a larger amount of boilerplate.

I'm just talking about the benefits here. There is also a cost to expanding the language. The costs might outweigh the benefits, but it doesn't mean that the benefits don't exist.

Re: Coroutines for Go

#162

It looks like a lot of people are missing the point here. Yes a coroutine library would be a worse/more cumbersome way to do concurrency than the go keyword. The use case motivating all the complexity is function iterators, where `range` can be used on functions of type `func() (T, bool)`. That has been discussed in the Go community for a long time, and the semantics would be intuitive/obvious to most Go programmers.…

Why not just range (or use an switch) over a channel and have a go routine running that pushes values into the channel?

I still don’t see the need for coroutines.

Re: Coroutines for Go

#163

I have written Go professionally for many years now and don't want to see it become something like the Python Twisted / Tornado / whatever frameworks. The go keyword nicely prevents the annoying function coloring problem, which causes quite a bit of pain. Sometimes in high performance contexts I'd like to be able to do something like e.g. per CPU core data sharding, but this proposal doesn't scratch those kinds of it…

Coroutines and goroutines fill different niches. The latter already fill the niche the likes of Twisted fill. There's nothing here trying to pull anything akin to async/await into Go. Coroutines will fill a different nice more akin to Python's generators. There are a whole bunch of places where this could dramatically cut down on memory usage and code complexity where you have a composable pipeline of components you…

I have had some experience with wire protocols that might benefit from coroutines. If I use goroutines, I have to use sync or channels, and then be careful. If I use state machines, it can be cumbersome. I suppose we will see.

Re: Coroutines for Go

#164
post #135

Earlier quoted context omitted.

I would prefer to add a `yield` param to functions so it can better interact with the current type system. This means that for a function to yield, it needs to have the so called `yield` param and you can only yield inside a yield function functions with the same yield signature or does not contain a signature at all. So the example would be rewritten into something like: x := func(:z int) { for { z++ :- z } } for y…

Sure, as long as I can close over a yield object. There is no reason for filter and map to know that the last function parameter takes a continuation.

But then, how could you guarantee type safety?

This yield is not an object, it is handling the execution context to another stack.

Re: Coroutines for Go

#165
post #75

Earlier quoted context omitted.

Coroutines and goroutines fill different niches. The latter already fill the niche the likes of Twisted fill. There's nothing here trying to pull anything akin to async/await into Go. Coroutines will fill a different nice more akin to Python's generators. There are a whole bunch of places where this could dramatically cut down on memory usage and code complexity where you have a composable pipeline of components you…

For sure cut down code complexity for the single clever code writer who wanted to be fancy. Not so sure about all the readers that will come afterwards.

Not at all. I often have to slurp in large amounts of data to be processed in some way. If you don't want to use huge amounts of memory for doing so, you either need to (a) write some horribly obtuse code or (b) use coroutines. Coroutines allow you do this in a more natural and composable way.

Anything involving a lexer and parser is a good example of this, and exactly one of the use cases given in the example. With coroutines, the lexer can take some input and emit a series of tokens which the parser can consume on the fly without any need to do any complex interleaving of the parser and lexer code. You also gain the ability to stop lexing early in case the parser encounters an issue.

I'm not sure what kinds of software you work on, but this is little more complicated or clever than Unix shell pipelines.

Re: Coroutines for Go

#166

Reading the comments makes me feel bittersweet. - Many people consider coroutines and green threads to be more or less the same thing, when they both have their pros and cons. - The fact that the omission of iterators is even acceptable in the Go community saddens me. They seem to deliberately refuse any feature that might make the language even slightly more complex, in the name of simplicity. But hey, at least they…

I wouldn’t confuse HN with “the Go community”. The head of the Go team wrote this post. Will the coro package proposed in the post be added exactly as written? Maybe, but probably not exactly as written. Will something like it be added? I would be willing to bet money on it, yes. How long will it take? I’d say at least a year (release in Go 1.23 in August of 2024), maybe a little longer. I don’t think it could be muc…

Given Go's history, there's a moderately high chance that this will be in a PR and immediately merged within the next few hours. They're a bit bipolar on "listen, wait, debate" vs "we just wrote about a new thing, it's already built and in stdlib but is largely undocumented"

Re: Coroutines for Go

#167
post #164

Earlier quoted context omitted.

Sure, as long as I can close over a yield object. There is no reason for filter and map to know that the last function parameter takes a continuation.

But then, how could you guarantee type safety? This yield is not an object, it is handling the execution context to another stack.

It is a delimited one-shot continuation. Delimited continuations are first class objects like any other and it should be possible to close over them.

Re: Coroutines for Go

#168
post #81

Earlier quoted context omitted.

In practice the difference would be closer to: getNext := iterableThing.Iterator() for { next, ok := getNext() if !ok { break } ... } vs. for next := range iterableThing.Iterator() { ... } One advantage is that it's slightly shorter, which matters for very common patterns--people complain about `err != nil` after all. Another advantage is there isn't another variable for everyone to name differently. Another advantag…

I think more idiomatic go for the first case would be: getNext := iterableThing.Iterator() for next, ok := getNext(); ok; next, ok = getNext() { ... } Which, yeah, the range cleans it up a bit, but it's not doing quite as much work as you're implying.

Don't forget that the important bit in Go is readability of the code. To me the range form is much easier to reason about than this for loop.

Re: Coroutines for Go

#169
post #122

Earlier quoted context omitted.

Well, what was wrong with: for { next :=

Horrible overhead. If the loop does something simple, like summing integers, 99% of time will be spent switching between goroutines. From TFA: "Because scheduling is explicit (without any preemption) and done entirely without the operating system, a coroutine switch takes at most around ten nanoseconds, usually even less. Startup and teardown is also much cheaper than threads." "For this taxonomy, Go's goroutines are…

I'm responding to a comment asking for a justification for sugar for function call based iteration. My comment is an attempt to draw a parallel to the need for sugar for channel based iteration. I'm not trying to suggest channel based iteration as an alternative to coroutines.

Re: Coroutines for Go

#170
post #77
post #18

Earlier quoted context omitted.

"Enormous amount of overhead" is the operative phrase. In general, you want your concurrency operations to be significantly smaller than the payload of the operation. In the case of using channels as iterators with goroutines behind them, it works fine for something like a web page scraper, where the act of fetching a web page is enormously larger than a goroutine switch, but as a generalized iteration mechanism it's…

But if your iteration is so fast then you don’t need a channel at all. Just use a plain for loop.

Then you lose the separation of iteration from the looping construct.

You can use a function or a method, but you lose the nice continuation/generator ability to write a function that can do complicated yields without having to write the state machine yourself, plus you run a risk that the call won't inline in which case you're incurring non-trivial function call overhead.

The problem with iteration in Go isn't that you can't solve any given individual problem, the problem is that you can't solve all of them simultaneously the way you can in Rust or Python. (Though one of these days I want to get around to benchmarking Python's iteration versus Go channel-based iteration, I'm not actually sure which would win. What Go considers dangerously slow can still be baseline performance for other languages.) So you can get a defeat-in-detail sort of thing where a person cites a problem, and someone posts as solution to that, and then they cite another problem, and there's a solution for that, and then there's another problem, and a solution is posted for that, and all the solutions do indeed more-or-less solve the given problem... but you can't combine them into one.

Post reply on HN