> To see if the the
> race detector would find this potential bug for me, I ran the code with the
> mutex(s) commented out with the -race flag on and didn't get a warning.
Did you make some concurrent requests? The race detector only tells
you about races that happen, so you need to excercise the concurrent
code paths in some way (possibly in a test or by selectively turning
on -race in a production-like environment).
A couple of general thoughts:
(1) The primary way to know whether a library you're using will call
your code concurrently from multiple goroutines is via documentation.
The net/http documentation, for instance, explains that Serve creates
a goroutine for each connection. Any other library you use should
clearly explain this if it's the case.
(2) net/http and other server packages are a slightly unusual case --
there are many libraries that exist, but most don't call your code
concurrently. (Even packages that invoke provided callbacks are
themselves a minority.) If I use a package that, say, interfaces with
a database or implements a graph algorithm, it would be quite strange
if it used concurrently-invoked callbacks.
While learning Go from the book "The Go Programming Language", by Addison-Wesley I was working through an example and was taken back by how easy it is to cause a data race.
On Thursday, June 23, 2016 at 6:44:22 PM UTC-6, Caleb Spare wrote:> To see if the the
> race detector would find this potential bug for me, I ran the code with the
> mutex(s) commented out with the -race flag on and didn't get a warning.
Did you make some concurrent requests? The race detector only tells
you about races that happen, so you need to excercise the concurrent
code paths in some way (possibly in a test or by selectively turning
on -race in a production-like environment).I just accessed the endpoint from multiple browsers, but no formal tests.
A couple of general thoughts:
(1) The primary way to know whether a library you're using will call
your code concurrently from multiple goroutines is via documentation.
The net/http documentation, for instance, explains that Serve creates
a goroutine for each connection. Any other library you use should
clearly explain this if it's the case.That makes sense, but seems to be a little fragile. For example, if the lib wasn't originally concurrent, then is changed, it would be easy to get into a bad situation. It makes me want to just wrap every variable in a Mutex to be safe. I'm guessing that the pattern is to keep Go programs as small as possible so you can track all the corner cases effectively in your own mental model.
(2) net/http and other server packages are a slightly unusual case --
there are many libraries that exist, but most don't call your code
concurrently. (Even packages that invoke provided callbacks are
themselves a minority.) If I use a package that, say, interfaces with
a database or implements a graph algorithm, it would be quite strange
if it used concurrently-invoked callbacks.As I ponder this; I wounder if some tooling could be added to the compiler or an outside utility that would scan all the used libraries, and notify you that the libraries/functions are concurrent.For example:--------------------------------------------------------------------------------------------------------go run --chk_concurrent mylib.goNotice: "net/http" calls concurrent operations on the Handle function.--------------------------------------------------------------------------------------------------------Thanks again for the feedback!--Nick
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
It makes me want to just wrap every variable in a Mutex to be safe.
I'm guessing that the pattern is to keep Go programs as small as possible so you can track all the corner cases effectively in your own mental model.
The question to ask is who does the concurrency. In the case of map, if the user is the one accessing the map concurrently, then it is the user's responsibility to ensure the map is concurrent safe. If the map internally implements some concurrent processing, then the map has the responsibility to ensure data integrity during the concurrent processing. The map's implementation should be invisible to the user.
That is a lofty goal, and not always achievable, many libraries are not self contained and often wrap other non-go libraries or device integration libraries that don't support that model. What people do inside a library should not be a language feature, otherwise the language is becoming overly opiniated.