循序渐进学go语言的协程和通道

2018-10-31  本文已影响0人  爱摄影_6bd0

本例来自于《go语言实战》,从这个例题开始,我们不断迭代,不断优化,做出我们想要的程序。
eg1:
'''
package main

import (
"fmt"
"sync"
)

func main() {
var wg sync.WaitGroup
wg.Add(2)
fmt.Println("Start sub goroutines")
go func() {
for count :=0; count <3; count++{
for char:='a';char<'a'+26;char++{
fmt.Printf("%c",char)
}
}
wg.Done()
}()
go func() {
for count :=0; count <3; count++{
for char:='A';char<'A'+26;char++{
fmt.Printf("%c",char)
}
}
wg.Done()
}()
wg.Wait()
fmt.Println()
fmt.Println("main goroutine over")
}
'''
由于并发程序的缘故,导致结果每次都不一样,输出大致结果如下:
Start sub goroutines
ABCDEFGHIJKLMNOPQRSTUVWXabcdefghYZABCDEijklmnopqrFGHstuvwxyIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
main goroutine over

中间的匿名函数明显的我们要提出来,做成一个独立的函数。那就这么干,看看会出现什么情况。
eg2:
package main

import (
"fmt"
"sync"
)

func main() {
var wg sync.WaitGroup
wg.Add(2)
fmt.Println("Start sub goroutines")
go printer('a',wg)
go printer('A',wg)

wg.Wait()
fmt.Println()
fmt.Println("main goroutine over")

}

func printer(prefix rune,wg sync.WaitGroup) {
go func() {
for count := 0; count < 3; count++ {
for char := prefix; char < prefix+26; char++ {
fmt.Printf("%c", char)
}
}
wg.Done()
}()
}
代码看起来干净多了,但是效果呢?我们看看运行结果。
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc00004c088)
C:/Go/src/runtime/sema.go:56 +0x40
sync.(*WaitGroup).Wait(0xc00004c080)
C:/Go/src/sync/waitgroup.go:130 +0x6b
main.main()
E:/mygo/goaction/goRoutine/goroutine.go:15 +0x10e
Start sub goroutines
abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzwxyzabcdefghijklmnopabcdefghqrstuvwijklmnoxyzpqrstuvwxyz
Process finished with exit code 2
what?怎么会这样。我们仔细看看,通过E:/mygo/goaction/goRoutine/goroutine.go:15 +0x10e的提示,我们发现可以看到,问题出在wg.wait()。为什么?因为永远等不到wg的计数为0. wg的计数器的减少是由 wg.done()完成的,这一句语法也没有问题,问题在哪里呢?因为是值传递,不是应用传递,导致出现错误。把函数的形式参数修改为指针,调用的时候直接取wg的地址OK了。直接看代码
package main

import (
"fmt"
"sync"
)

func main() {
var wg sync.WaitGroup
wg.Add(2)
fmt.Println("Start sub goroutines")
go printer('a',&wg)
go printer('A',&wg)

wg.Wait()
fmt.Println()
fmt.Println("main goroutine over")

}

func printer(prefix rune,wg *sync.WaitGroup) {
go func() {
for count := 0; count < 3; count++ {
for char := prefix; char < prefix+26; char++ {
fmt.Printf("%c", char)
}
}
wg.Done()
}()
}
结果没问题。
这段代码看起来没问题了,如果我不想在每个子goroutine中输出,而是要集中统一输出结果又该怎么做呢?对于go语言,当然要选择channel.该怎么做呢?下回分解。

上一篇下一篇

猜你喜欢

热点阅读