3 ms·
I don't know Go, so I don't really understand what the issue is with the code you posted. In Rust, the closure used to spawn a new thread needs to own its envir
by tatterdemalion 10y ago
I don't know Go, so I don't really understand what the issue is with the code you posted. In Rust, the closure used to spawn a new thread needs to own its environment; if it does then there's no problem. If it doesn't that's a data race and you have a compile time error about it.
- lobster_johnson 10y agoThe error in the Go snippet is that "v" is a single memory location shared throughout the loop. The closure doesn't get a copy, so what usually ends up happening is that every goroutine gets the last value (since the goroutines are probably not scheduled until the end of the loop). This problem doesn't just affect loops, of course: A goroutine can access any local environment outside its scope, and local variables can mutate. The worst surprise I ever encountered was this (simplified): func makeWorkersDocomplicatedStuff() ch := make(chan string) defer func() { if ch != nil { close(ch) } } for i := 0; i < numWorkers; i++ { go func() { for { select { case s := <-ch: // ... } } } } close(ch) ch = nil // ... More stuff ... } What will happen here is that the goroutines will all block forever, because "ch" becomes nil, and in Go, polling a nil channel will block forever (it's an interesting design choice in such a strict language). Rewriting and refactoring this was trivial enough, but catching it was time wasted. Lessons learned: (1) Be scrupulous about closure environments, (2) be super careful about nil channels, and (3) try to avoid defers whose concerns don't fully encapsulate the function body (so defers in the middle of a function is often code smell).
- tatterdemalion 10y ago> The error in the Go snippet is that "v" is a single memory location shared throughout the loop. In Rust this is not true. However, the same concept applies - say it was a variable from outside the loop. In that case, you would get a clear compile time error about moving the value into the thread's closure more than once. A similar error would apply if you iterated over a container by reference (instead of by value).