From a waitgroup example, the upvalue of the go language can be transferred

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

The external variables of the Go language's closure capture, I'm still accustomed to Lua, called Upvalue, after all, go draws on a lot of LUA features.

Let's take a look at five almost the same code snippet first.

package mainimport ("log""sync")func main() {wg := sync.WaitGroup{}for i := 0; i < 5; i++ {wg.Add(1)go func(wg sync.WaitGroup, i int) {log.Printf("i:%d", i)wg.Done()}(wg, i)}wg.Wait()log.Println("exit")}

Output:

go run wgtest1.go 2017/01/01 23:43:08 i:42017/01/01 23:43:08 i:22017/01/01 23:43:08 i:32017/01/01 23:43:08 i:12017/01/01 23:43:08 i:0fatal error: all goroutines are asleep - deadlock!goroutine 1 [semacquire]:sync.runtime_Semacquire(0xc42000a2ac)/usr/local/Cellar/go/1.7.4_1/libexec/src/runtime/sema.go:47 +0x30sync.(*WaitGroup).Wait(0xc42000a2a0)/usr/local/Cellar/go/1.7.4_1/libexec/src/sync/waitgroup.go:131 +0x97main.main()/Users/linkerlin/gos/wgtest1.go:17 +0xbaexit status 2

This is because the waitgroup in the Go language is an object that cannot be copied after the first use. The main function of Goroutine is actually the method of transmitting the value of Waitgroup. It is particularly important to note that the output of the next i is in line with expectations.

OK, let's look at the second piece of code:

package mainimport ("log""sync")func main() {wg := sync.WaitGroup{}for i := 0; i < 5; i++ {wg.Add(1)go func() {log.Printf("i:%d", i)wg.Done()}()}wg.Wait()log.Println("exit")}

Output:

go run wgtest2.go 2017/01/01 23:48:10 i:52017/01/01 23:48:10 i:52017/01/01 23:48:10 i:52017/01/01 23:48:10 i:52017/01/01 23:48:10 i:52017/01/01 23:48:10 exit

There is no deadlock, but the output of the I value is wrong. Because, the go language inside Upvalue is quoted. Goroutine multiple captures are the same i.

Again, let's look at the third piece of code:

package mainimport ("log""sync")func main() {wg := sync.WaitGroup{}for i := 0; i < 5; i++ {wg.Add(1)go func() {log.Printf("i:%d", i)wg.Done()}()}wg.Wait()log.Println("exit")}

Output:

go run wgtest3.go 2017/01/01 23:51:46 i:52017/01/01 23:51:46 i:52017/01/01 23:51:46 i:52017/01/01 23:51:46 i:42017/01/01 23:51:46 i:52017/01/01 23:51:46 exit

There is no deadlock, I is the wrong number. Because the I of Upvaule is ByRef pass. Note that here there are 4 5 and one 4, the final output what is actually random, depending on the operating system and hardware. The faster the goroutine is dispatched, the more likely it is to have a smaller output than 5.

Again, let's look at the fourth piece of code:

package mainimport ("log""sync")func main() {wg := sync.WaitGroup{}for i := 0; i < 5; i++ {wg.Add(1)go func(wg *sync.WaitGroup, i int) {log.Printf("i:%d", i)wg.Done()}(&wg, i)}wg.Wait()log.Println("exit")}

Output:

go run wgtest4.go 2017/01/01 23:56:51 i:12017/01/01 23:56:51 i:02017/01/01 23:56:51 i:42017/01/01 23:56:51 i:22017/01/01 23:56:51 i:32017/01/01 23:56:51 exit

Everything is normal and in line with expectations. However, this kind of writing is rather cumbersome. First, instead of using closures to build a higher-order function, it reverts to the traditional upvalue, which is too heavy for the mind of the person who wrote the code, and the values and references to be specified manually, and also in the Goroutine main function entry one by one. So what should we recommend as a way of writing?

Finally, let's look at the fifth piece of code:

package mainimport ("log""sync")func main() {wg := sync.WaitGroup{}for i := 0; i < 5; i++ {func(i int) {wg.Add(1)go func() {log.Printf("i:%d", i)wg.Done()}()}(i)}wg.Wait()log.Println("exit")}

Output:

go run wgtest5.go 2017/01/02 00:03:32 i:42017/01/02 00:03:32 i:02017/01/02 00:03:32 i:12017/01/02 00:03:32 i:22017/01/02 00:03:32 i:32017/01/02 00:03:32 exit

The same things are normal. However, in the fifth code, the main function of Goroutine is not a parameter. The quoted situation takes advantage of the upvalue, and the I variable that needs to be passed is copied with the parameters of an outsourced function. Because each loop invokes the outsource function, it duplicates the value of I, although the goroutine main function in the inner layer captures I through upvalue, but each captures the I copy of the outsourced function.

In summary, in the consideration of reducing the mental burden of developers, I suggest:

1. The Goroutine entry function inside the go language does not pass arguments.

2. All ref parameters are captured by Upvalue.

3. If you want to pass a value, you can wrap a function outside of goroutine and pass the value of the parameter to the outsourced function. The name of the parameter remains the same name.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.