* Fei Ding <fding...@gmail.com> [160918 02:58]:
> Thanks, Marvin, I've learned a lot from your reply. And, I've written more
> code, like:
> 
> a, b, c := 1, 2, 3
> > slice1 := []int{a, b, c}
> > for _, n := range slice1 {
> > go func(n *int) {fmt.Println(*n)}(&n)
> > }
> 
> 
>  It seems that pass *n's address *in the code above will make a data race,
> which you have already explained why. But still, I have another question:
> If the coder do really want the addresses of elements in slice, how to do
> it correctly?

* Marvin Stenger <marvin.stenge...@gmail.com> [160918 07:12]:
> https://play.golang.org/p/9LQMDrDIOv should work.

Marvin Stenger gives two good solutions in the above link.  I will
explain what each does and why you might use one over the other.

    for i, _ := range values {
        go values[i].print()
    }

In this case, the expression values[i].print is evaluated to determine
the function to be scheduled, so the function that is scheduled is the
print method with an implied first argument of &values[i].  This
expression is evaluated prior to scheduling, so neither the variable
values nor the variable i are referenced in the goroutine.  However, the
value of &values[i] is a pointer into the backing array for the slice,
which will be important in choosing which solution to use.

    for _, v := range values {
        w := v
        go w.print()
    }

In the second case, although the same v is reused for all iterations of
the loop, a new w is created each time through the loop.  The assignment
to v at the beginning of the loop makes a copy of the slice element and
puts it in v.  Then it is copied a second time and stored in w.  (The
compiler may be able to optimize the generated code to avoid making two
copies.)  Now the function call that is scheduled is a call to the print
method with an implied first argument of &w.  Because each iteration of
the loop uses a new variable w, each goroutine has its own copy of the
slice element associated with the iteration of the loop in which the
goroutine was created.

The primary consideration in choosing between these two solutions is
whether or not the goroutine can safely access the slice element in the
backing array.  If it can, use the first solution.  If it cannot, either
because the backing array might be modified or because the element
itself is not safe to reference concurrently, then use the second
solution.  I would probably modify the second solution like this:

    for i, _ := range values {
        var w = values[i]
        go w.print()
    }

This doesn't rely on the compiler's ability to optimize copying the
element twice into copying it only once, and it is just as clear to the
next programmer who reads your code.

...Marvin

-- 
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+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to