Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
package main
import (
"context"
"fmt"
)
func gen(ctx context.Context) <-chan int {
ch := make(chan int)
go func() {
var n int
for {
select {
case <-ctx.Done():
return
case ch <- n:
n++
}
}
}()
return ch
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
for n := range gen(ctx) {
fmt.Println(n)
if n == 5 {
cancel()
break
}
}
}

kylehq commented Jan 31, 2017

Hi Jaana, thanks so much for putting all these together. I'd like to ask a question in regards to the above and your post https://rakyll.org/leakingctx/.

We can avoid the problem by signalling the internal goroutine with a stop channel but there is a better solution: cancellable contexts.

Can you explain to me why it's better to pass a context to the gen() function rather than a stop chan struct{}? The gen function would still have the same method changes, both ways will use a single dependency and the stop can also be deferred to ensure no goroutine leaks.

Is this just a new convention? Is there a performance gain to using the context instead? Any thoughts would be most welcome =]
Thanks Kyle

Xeoncross commented Jul 29, 2017

@kylehq, looks like the process is more about handling passing channels over a number of functions (some of which may be third party) like when dealing with a HTTP request: https://blog.golang.org/context/google/google.go

Still looks like a standard stop chan struct{} would work, but the context can also pass additional values all the way through so it combines a signaler + values.

gerep commented Nov 24, 2017

Is it required to call cancel() inside the n == 5 conditional even when you are using break to escape the loop and using defer cancel()?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment