-
Notifications
You must be signed in to change notification settings - Fork 570
Goroutine runs forever #229
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
Comments
I can reproduce. http://www.gopherjs.org/playground/#/xn99smXFsK is the GopherJS playground link. I'm guessing that Go kills all running goroutines when main() returns, but GopherJS may not be doing that. |
For reference, as a workaround, if you modify the code to manually wind down the goroutines when main() returns, it behaves as expected. E.g., see http://www.gopherjs.org/playground/#/pWLkbHaHOa. |
Good point, I will do this for now as a workaround ! |
The program terminates when main returns. Goroutines aren't explicitly killed, it's a side effect of, well, the program not running anymore. With GopherJS in the browser, the "application" terminates when the page is closed. I'm not sure if GopherJS should shut itself down when main returns. |
Those are very good points. It may make sense to keep current behavior as WAI. Consider a script that does something like: func main() {
item.AddEventListener("click", false, func(event dom.Event) {
// Do something on every click.
})
} Wouldn't it make sense for the click callback handler continue to work even after main() returns? Or should we require users to place a |
In my opinion GopherJS should follow (as until now) Go's behaviour as close as technically possible, otherwise we are entering a gray area which makes it hard to predict GopherJs created code, often copied from server side code (Isomorphism). Who wants ever running code uses "for {} " or hooks up event listeners to the Dom, which indeed only get stopped on page leave. |
Since event listeners continue running after main() returns, they can execute more Go code and spawn new goroutines, etc. I agree that GopherJS should follow Go's behavior, and I think it's most consistent if goroutines and other potential code continues to work and run until program is terminated. In the case of OS X, etc., program is terminated when either main() returns or os.Exit() is called. In browser, program is terminated when page is closed. What do you think? |
What about the following piece of code?
When you say that hooks still work even after main returns, you're already deviating from "normal" Go, where the program terminates, so might as well keep goroutines running. Our use of Go is more like the planned shared library support for Go. In fact, https://docs.google.com/document/d/1tU_yNmwu1raKZm9atHJ8THiQizkYTKykdWraIb15TSE/edit#heading=h.qnind36h4b6s discusses this exact issue (the Initialization/main.main section). One of the possible solutions they mention matches our current behaviour. Most of the other solutions that would also work for us just don't call it The lifetime of goroutines should be bound to the lifetime of the "application", which in our case is the page loaded in a browser. |
I'm in agreement with @dominikh on this.
This appears to be the only consistent solution (and simplest). |
Hi @dominikh , without the "for {}" loop your channel receives only once, was this by intention ? @shurcooL : you are right, I meant putting the for loop in a goroutine, see further down I have no problem in understanding the following program: The receiving goroutine continues active since the click event gets hooked up to the dom and thereby the main loop continues running. This is at least my understanding for such a use case where the dom is involved, and from what I know Dart make the same assumptions. In my first playground example no dom is involved, so I need to know for what reasons gopherjs continues with active goroutines. package main
//html page imports jquery.js and has a #someButtonId Button
import "github.com/gopherjs/gopherjs/js"
var jQuery = js.Global.Get("jQuery")
func main() {
ch := make(chan int)
go func() {
for {
print("prepared to receive...")
println(<-ch)
}
}()
jQuery.New("#someButtonId").Call("on", "click", func(this *js.Object) {
print("sending now...")
ch <- 1
})
} |
It doesn't make a difference, the sole purpose was to show a goroutine that needs to outlive main. Whether it needs to outlive it for one iteration or many doesn't matter.
There's no "main loop", and no, main doesn't continue running. jquery.New().Call returns instantly. main returns afterwards. What lives on is a callback. If goroutines did terminate after main returns, the goroutine in your example would also terminate; main returns. In fact, GopherJS doesn't, and shouldn't have, an understanding of the DOM, or have any insight into what the jquery package is doing.
|
Two more examples, one even without any DOM interaction.
and
|
@dominikh 👍 Thanks for your explication, now I have a better understanding of GopherJs' implementation of goroutines |
@rusco You are right that the Go specification says However, I think in most cases, e.g. the examples above, this is not the behaviour that you'll want in the browser environment. Maybe the best way to think of it is that your program's For deadlock detection (all goroutines asleep), I already need to look for callbacks. Deadlock detection gets simply disabled as soon as you pass a func to JS. I think this is fine for deadlock detection, since it is only there to display some more helpful error, but I'd rather not change the termination behaviour based on this. |
Hi Richard, |
@rusco Wow, this issue is really old. Sorry about that. I added some documentation on the |
http://play.golang.org/p/xn99smXFsK
Compare the behaviour in go vs. gopherjs: After the time.Sleep() interval the "debounce" goroutine stops in go but not in gopherjs
The text was updated successfully, but these errors were encountered: