Goroutine in a for loop: Closure versus direct

186 views
Skip to first unread message

Amit Saha

unread,
Feb 25, 2017, 3:48:09 AM2/25/17
to golang-nuts
Hello,

When spawning goroutines in a for loop - is there any reason to prefer approach #1 below versus #2 or vice-versa?

Approach #1: Using a closure

func printme(val int) {
 // Do something with val
}

func main() {
slice := []int{1, 23, 100, 101}
        for _, val := range slice {
go func(val int) {
printme(val)
}(val)
}
}

Approach #2: Direct

func printme(val int) {
 // Do something with val
}

func main() {
slice := []int{1, 23, 100, 101}
        for _, val := range slice {
go printme(val)
}
}


I think both these approaches are fine, but just wanted to check.

Thanks for your inputs.

Best Wishes,
Amit.




Jan Mercl

unread,
Feb 25, 2017, 4:03:26 AM2/25/17
to Amit Saha, golang-nuts
> I think both these approaches are fine, but just wanted to check.

They're not, #2 has a data race.

--

-j

Amit Saha

unread,
Feb 25, 2017, 4:30:20 AM2/25/17
to Jan Mercl, golang-nuts
On Sat, Feb 25, 2017 at 8:03 PM, Jan Mercl <0xj...@gmail.com> wrote:
>> I think both these approaches are fine, but just wanted to check.
>
> They're not, #2 has a data race.

Thanks, can you please explain how or point me to a doc/post explaining it?


>
> --
>
> -j



--
http://echorand.me

Ayan George

unread,
Feb 25, 2017, 5:59:15 AM2/25/17
to golan...@googlegroups.com


On 02/25/2017 03:48 AM, Amit Saha wrote:
>
> I think both these approaches are fine, but just wanted to check.
>

tl;dr: I think the second example is the way to go.

I'm somewhat new to Golang so please someone correct me if I'm wrong.

Neither of your examples are closures and, AFAIK, they're both
effectively the same. As Jan mentioned -- if you actually used a
closure like below, there *would* be a data race:

func main() {
slice := []int{1, 23, 100, 101}
for _, val := range slice {
go func() {
fmt.Printf("val = %d\n", val)
}()
}
}

Notice the goroutines access the same 'val' variable concurrently
while 'val' changes.

I don't think your code presents a race because it copies 'val' when it
is passed as a parameter to printme() or to your anonymous function.

I think the choice to use an anonymous function and the choice to use a
closure have their own considerations.

You typically choose to use an anonymous function if the code
you want to execute is relatively short and if the code is something
that you don't plan to re-use.

Your example is short but it is only one statement so wrapping it in an
anonymous function doesn't buy you anything. If it were two or three
statements I think it'd be worthwhile.

-ayan

Amit Saha

unread,
Feb 25, 2017, 7:32:10 AM2/25/17
to Ayan George, golang-nuts
On Sat, Feb 25, 2017 at 9:58 PM, Ayan George <ay...@ayan.net> wrote:
>
>
> On 02/25/2017 03:48 AM, Amit Saha wrote:
>>
>> I think both these approaches are fine, but just wanted to check.
>>
>
> tl;dr: I think the second example is the way to go.
>
> I'm somewhat new to Golang so please someone correct me if I'm wrong.
>
> Neither of your examples are closures and, AFAIK, they're both
> effectively the same. As Jan mentioned -- if you actually used a
> closure like below, there *would* be a data race:
>
> func main() {
> slice := []int{1, 23, 100, 101}
> for _, val := range slice {
> go func() {
> fmt.Printf("val = %d\n", val)
> }()
> }
> }
>

Thanks for the reply. Yes, I have learned the same about issues with
closures. Yes. indeed, my example #1 is using an anonymous function,
not a closure. Jan mentioned though #2 has a race, and that got me
confused.


> Notice the goroutines access the same 'val' variable concurrently
> while 'val' changes.
>
> I don't think your code presents a race because it copies 'val' when it
> is passed as a parameter to printme() or to your anonymous function.
>
> I think the choice to use an anonymous function and the choice to use a
> closure have their own considerations.
>
> You typically choose to use an anonymous function if the code
> you want to execute is relatively short and if the code is something
> that you don't plan to re-use.
>
> Your example is short but it is only one statement so wrapping it in an
> anonymous function doesn't buy you anything. If it were two or three
> statements I think it'd be worthwhile.

Indeed, that makes sense. Thank you.


>
> -ayan
>
> --
> You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/hFrnOexAw3o/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.



--
http://echorand.me

Dan Kortschak

unread,
Feb 26, 2017, 6:21:15 PM2/26/17
to Jan Mercl, Amit Saha, golang-nuts
On Sat, 2017-02-25 at 09:03 +0000, Jan Mercl wrote:
> They're not, #2 has a data race.


There is no race, the go routine is not a closure.

simon place

unread,
Feb 26, 2017, 7:24:48 PM2/26/17
to golang-nuts
IFAIK they are the same, and could be compiled to the same thing.

it seems to me a closure with its whole context just passed on, isn't doing anything.

Reply all
Reply to author
Forward
0 new messages