8 ms·
I think it's only consistent in play.golang.org because results are cached: https://blog.golang.org/playground https://blog.golang.org/playground. If I run it
by modernerd 7y ago
I think it's only consistent in play.golang.org because results are cached: https://blog.golang.org/playground https://blog.golang.org/playground.
If I run it locally it's not consistent:
go run lock/main.go
[3 0 1 2 5 4 6 9 7 8] 10⏎
go run lock/main.go
[1 5 6 7 8 0] 6⏎
go run lock/main.go
[0 3 1 2 4 5 6 7 8] 9⏎
Here's a version that does work for me: https://play.golang.org/p/b6bRb9pgIGZ https://play.golang.org/p/b6bRb9pgIGZ
The issue is that appending to slices concurrently is not safe, so you have to use a lock around the append or similar.
- iamjfu 7y agoTIL. That's a huge flaw. Thanks so much for your response!
- modernerd 7y agoWelcome! It's the same for other data structures, by the way (not just slices) — maps are not safe for concurrent writes either. (The rationale seems to be that users of the data types can choose whether to make them safe for concurrent use or not depending on the use case.) I found this helpful: https://youtu.be/29LLRKIL_TI?t=1340 https://youtu.be/29LLRKIL_TI?t=1340
- masklinn 7y ago> The rationale seems to be that users of the data types can choose whether to make them safe for concurrent use or not depending on the use case. Also that for most uses a concurrent map is way overkill, and a thread-safe one is both costly and basically useless (hence the Java folks not keeping the thread-safety when migrating from Hashtable to HashMap). On the other hand they're kinda shit given how awful non-builtin data structures are in Go, and how easy it is to "leak" maps between goroutines.
- vips7L 7y agoHashtable used a giant mutex when locking.. it was just slow. Especially when compared to ConcurrentHashMap.
- irq-1 7y agoThey added sync.Map > Map is like a Go map[interface{}]interface{} but is safe for concurrent use by multiple goroutines without additional locking or coordination. Loads, stores, and deletes run in amortized constant time. https://golang.org/pkg/sync/#Map https://golang.org/pkg/sync/#Map
- empath75 7y agoIf you try to run a naive version of this in rust, the compiler won't even run it. https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=59d2eb657b3cbd5da5914beb6aa98f08 https://play.rust-lang.org/?version=stable&mode=debug&editio... I'm a beginner at rust, but this is the version I came up with that compiles and works: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=83ec90561271b46abc8df451991fd4f0 https://play.rust-lang.org/?version=stable&mode=debug&editio...
- DougBTX 7y agoIn a way this supports the argument for the "Do not communicate by sharing memory; instead, share memory by communicating" mantra, as in a language with no compile-time checks for incorrect use of shared memory, it is very easy to get it wrong.
- modernerd 7y agoYes, it looks like the author has updated their post to say as much following the comments here.
- iamjfu 7y agoI have. I didn't have time to rewrite it (I'm working, and I didn't want to take it down) so I added a few caveats. I am going to research this more and follow up again. Thanks again to everyone for the great responses. I learned a lot from the comments here.
- shhsshs 7y agoResults are cached, but the main reason the example “works” is because the playground has GOMAXPROCS set to 1, meaning only a single goroutine will be running at any given point.
- modernerd 7y agoThat makes sense, thanks for the correction.