Please help me. I have block codes, It uses iteration to get the elements of the map, and use this element to create a listener on a port on a Linux machine, But Its execution exceeded my expectations. code show as below:
var srvs = map[string]struct {
id int
timezone string
connCfg string
conn net.Conn
}{"BrazilEastSrv": {id: 1, timezone: "Brazil/East", connCfg: "127.0.0.1:9007"},
"AustraliaDarwinSrv": {id: 2, timezone: "Australia/Darwin", connCfg: "127.0.0.1:9008"}}
var ch1 = make(chan int, 2)
func main() {
for k, srv := range srvs {
go func() {
if ln, err := net.Listen("tcp", srv.connCfg); err != nil {
log.Fatal(fmt.Sprintf("%s : %s conn failed,", k, srv.connCfg))
} else {
log.Println(fmt.Sprintf("%s:%s created, port:%s listened.", k, srv.connCfg[:9], srv.connCfg[10:]))
if conn, err := ln.Accept(); err != nil {
log.Fatal(srv.connCfg, " conn create fatal, errmsg=", err)
} else {
srv.conn = conn
defer srv.conn.Close()
log.Println("Accepted an access request from cli:", srv.conn.RemoteAddr(), ".")
handleMsg(srv)
}
}
}()
}
var brazilEastSrv, australiaDarwinSrv = <-ch1
log.Println(brazilEastSrv, australiaDarwinSrv)
}
output:
2017/12/07 11:45:48 AustraliaDarwinSrv:127.0.0.1 created, port:9008 listened.
2017/12/07 11:45:48 AustraliaDarwinSrv : 127.0.0.1:9008 conn failed,
exit status 1
Seen from the output content. It uses the last element of the iteration and reuses this element, Why does it have this problem?
But when I make some changes:
var srvs = map[string]struct {
id int
timezone string
connCfg string
conn net.Conn
}{"BrazilEastSrv": {id: 1, timezone: "Brazil/East", connCfg: "127.0.0.1:9007"},
"AustraliaDarwinSrv": {id: 2, timezone: "Australia/Darwin", connCfg: "127.0.0.1:9008"}}
var ch1 = make(chan int, 2)
func main() {
for k, srv := range srvs {
go func(srv struct {
id int
timezone string
connCfg string
conn net.Conn
}) {
//go func() {
if ln, err := net.Listen("tcp", srv.connCfg); err != nil {
log.Fatal(fmt.Sprintf("%s : %s conn failed,", k, srv.connCfg))
} else {
log.Println(fmt.Sprintf("%s:%s created, port:%s listened.", k, srv.connCfg[:9], srv.connCfg[10:]))
if conn, err := ln.Accept(); err != nil {
log.Fatal(srv.connCfg, " conn create fatal, errmsg=", err)
} else {
srv.conn = conn
defer srv.conn.Close()
log.Println("Accepted an access request from cli:", srv.conn.RemoteAddr(), ".")
handleMsg(srv)
}
}
//}()
}(srv)
}
var brazilEastSrv, australiaDarwinSrv = <-ch1
log.Println(brazilEastSrv, australiaDarwinSrv)
}
It behaves in line with my expectations, what caused that difference? Thank you for your explanation.
In the first version, your goroutine uses the variable srv
(and k
) which changes with each iteration of the loop, so you don't know what value your goroutine will see when it is executing. In the second version, you're passing srv
as an argument to the goroutine, so the variable srv
within the goroutine is no longer the same variable that is used in the loop.