Created
May 30, 2014 12:29
-
-
Save feyeleanor/ffd6d6ed5b32184c7281 to your computer and use it in GitHub Desktop.
Goroutine launch puzzler
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
. "fmt" | |
. "net/http" | |
) | |
const ADDRESS = ":1024" | |
const SECURE_ADDRESS = ":1025" | |
func main() { | |
message := "hello world" | |
HandleFunc("/hello", func(w ResponseWriter, r *Request) { | |
w.Header().Set("Content-Type", "text/plain") | |
Fprintf(w, message) | |
}) | |
Spawn( | |
func() { ListenAndServe(ADDRESS, nil) }, | |
func() { ListenAndServeTLS(SECURE_ADDRESS, "cert.pem", "key.pem", nil) }, | |
) | |
} | |
func Spawn(f ...func()) { | |
done := make(chan bool) | |
for _, s := range f { | |
go func() { | |
s() | |
done <- true | |
}() | |
} | |
for l := len(f); l > 0; l-- { | |
<- done | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
. "fmt" | |
. "net/http" | |
) | |
const ADDRESS = ":1024" | |
const SECURE_ADDRESS = ":1025" | |
func main() { | |
message := "hello world" | |
HandleFunc("/hello", func(w ResponseWriter, r *Request) { | |
w.Header().Set("Content-Type", "text/plain") | |
Fprintf(w, message) | |
}) | |
Spawn( | |
func() { ListenAndServe(ADDRESS, nil) }, | |
func() { ListenAndServeTLS(SECURE_ADDRESS, "cert.pem", "key.pem", nil) }, | |
) | |
} | |
func Spawn(http, https func()) { | |
done := make(chan bool) | |
go func() { | |
http() | |
done <- true | |
}() | |
go func() { | |
https() | |
done <- true | |
}() | |
<- done | |
<- done | |
} |
This took me a little while to figure out. The issue is that the function doesn't have a closure over the function s.
Try changing the body of the for loop in "This doesn't" to something like this.
for _, s := range f {
a := func(fun func()) {
fun()
done <- true
}
go a(s)
}
Go doesn't capture external variables.
Here is a better explanation that I found https://code.google.com/p/go-wiki/wiki/CommonMistakes
Edit: Changed i back to _
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
So, with these two programs the aim is to launch two goroutines and block program exit until they're both completed. In one goroutine we're launching an HTTP server, and in the other an HTTPS server.
In the version which works both servers launch and respond to traffic from a web browser.
In the version which doesn't work, the HTTP server completes as soon as the HTTPS server launches. The HTTPS server then responds to traffic from a web browser.
If I reverse the order of the passed functions, it's the HTTPS server which terminates and the HTTP server which works. So in other words, whichever server is launched first will terminate whilst the second server will run normally.
Any ideas on why the two pieces of code are behaving differently when they're apparently doing the same thing?