Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

context: WithTimeout seems to not release the goroutines created internally #20576

Closed
drgomesp opened this issue Jun 5, 2017 · 8 comments
Closed

Comments

@drgomesp
Copy link

drgomesp commented Jun 5, 2017

Please answer these questions before submitting your issue. Thanks!

What version of Go are you using (go version)?

1.8.1

What operating system and processor architecture are you using (go env)?

GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/drgomesp/go"
GORACE=""
GOROOT="/usr/local/Cellar/go/1.8/libexec"
GOTOOLDIR="/usr/local/Cellar/go/1.8/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/7j/l9t66rwd06d64lrgffpbct1m0000gn/T/go-build463779310=/tmp/go-build -gno-record-gcc-switches -fno-common"
CXX="clang++"
CGO_ENABLED="1"
PKG_CONFIG="pkg-config"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"

What did you do?

I have a simple implementation that uses context.WithTimeout, more or less like:

ctx, cancelFn := context.WithTimeout(context.Background(), time.Duration(time.Minute*1))
defer cancelFn()

select {
    case <-ctx.Done():
        // ...
        return
}

When I monitor the number of currently existing goroutines (using runtime.NumGoroutines()), it seems that whenever the WithTimeout() function gets called, it internally creates a goroutine to keep track of the time and eventually cancel the context (which makes sense, if you look at the internals (https://github.com/golang/go/blob/master/src/context/context.go#L401 and https://github.com/golang/go/blob/master/src/time/sleep.go#L170).

However, when the context is finished and the case statement is reached, the goroutine is not being released. It seems that it keeps running forever and the resources are not released properly.

If I change the implementation to use a simpler version of a timeout, without the context.WithTimeout(), more or less like:

select {
    case <-time.After(time.Minute*1):
        // ...
        return
}

Then the number of goroutines is the expected in the first place and nothing seems to leak.

What could be the problem? What am I missing?

What did you expect to see?

Expect the goroutine created internally to be released

What did you see instead?

Seems that the goroutine created internally is never released

@ALTree
Copy link
Member

ALTree commented Jun 5, 2017

https://golang.org/pkg/context/#WithTimeout

Canceling this context releases resources associated with it, so code should call cancel as soon as the operations running in this Context complete

ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
defer cancel()  // releases resources if slowOperation completes before timeout elapses

are you doing this?

@drgomesp
Copy link
Author

drgomesp commented Jun 5, 2017

Yes, forgive me I forgot to add that line of code. Cancel function is being called.

@ALTree
Copy link
Member

ALTree commented Jun 5, 2017

Cancel function is being called.

On every path?

If possible, please post an auto-contained reproducer that can be used to assess the problem.

@drgomesp
Copy link
Author

drgomesp commented Jun 5, 2017

The cancelFn gets called from within a different goroutine. Could that be the issue?

@ALTree
Copy link
Member

ALTree commented Jun 5, 2017

Again, it's hard to say without having the code and without knowing how, where and when you spawn the goroutine that cancels, and how and when it does it; but yes, that could be your issue.

@ALTree ALTree changed the title context.WithTimeout seems to not release the goroutines created internally context: WithTimeout seems to not release the goroutines created internally Jun 5, 2017
@drgomesp
Copy link
Author

drgomesp commented Jun 5, 2017

Here you go: https://play.golang.org/p/p68dFUVJhs

@drgomesp
Copy link
Author

drgomesp commented Jun 5, 2017

As a note, seeing the Timer implementation (internally used to handle the context termination after given amount of time has passed):

type Timer struct {
	C <-chan Time
	r runtimeTimer
}

Apparently, Timer.C is never closed, therefore it might leak?

EDIT: Weirdly enough, if I print the number of goroutines at the very beginning of the main function, it gives me 1 – so, in theory, no goroutine is leaking.

@drgomesp
Copy link
Author

drgomesp commented Jun 5, 2017

I'm closing this until we have more information to be able to confirm that it's an issue.

@drgomesp drgomesp closed this as completed Jun 5, 2017
@golang golang locked and limited conversation to collaborators Jun 5, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants