美文网首页
循序渐进学go语言的协程和通道

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

作者: 爱摄影_6bd0 | 来源:发表于2018-10-31 18:36 被阅读0次

    本例来自于《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.该怎么做呢?下回分解。

    相关文章

      网友评论

          本文标题:循序渐进学go语言的协程和通道

          本文链接:https://www.haomeiwen.com/subject/iagatqtx.html