Golang Goroutine不在通道内部运行

我正在尝试实现字数统计程序,但是第一步我遇到了一些问题。


这是我的代码:


package main


import (

    "fmt"

    "os"

    "bufio"

    "sync"

)


// Load data into channel

func laodData(arr []string,channel chan string,wg sync.WaitGroup) {

    for _,path := range arr {

        file,err := os.Open(path)

        fmt.Println("begin to laodData ", path)

        if err != nil {

            fmt.Println(err)

            os.Exit(-1)

        }

        defer file.Close()

        reader := bufio.NewReaderSize(file, 32*10*1024)

        i := 0

        for {

            line,err := reader.ReadString('\n')

            channel <- line

            if err != nil {

                break

            }

            i++

            if i%200 == 0 {

                fmt.Println(i," lines parsed")

            }

        }

        fmt.Println("finish laodData ", path)

    }

    wg.Done()

}


// dispatch data lines into different mappers

func dispatcher(channel chan string,wg sync.WaitGroup){

    fmt.Println("pull data 11")

    line,ok := <- channel

    fmt.Println(ok)

    for ok {

        fmt.Println(line)

        line,ok = <- channel

    }

    fmt.Println("pull data 22")

    wg.Done()

}


func main() {

    path := os.Args

    if len(path) < 2 {

        fmt.Println("Need Input Files")

        os.Exit(0)

    }

    var wg sync.WaitGroup

    wg.Add(2)


    channel := make(chan string)

    defer close(channel)


    fmt.Println("before dispatcher")

    go laodData(path[1:],channel,wg)

    go dispatcher(channel,wg)

    wg.Wait()


    fmt.Println("after dispatcher")

}

这是我的输出:


...


finish laodData  result.txt


throw: all goroutines are asleep - deadlock!


goroutine 1 [semacquire]:

sync.runtime_Semacquire(0x42154100, 0x42154100)

    /usr/local/go/src/pkg/runtime/zsema_amd64.c:146 +0x25

sync.(*WaitGroup).Wait(0x4213b440, 0x0)

    /usr/local/go/src/pkg/sync/waitgroup.go:79 +0xf2

main.main()

    /Users/kuankuan/go/src/mreasy/main.go:66 +0x238


慕少森
浏览 226回答 3
3回答

白衣非少年

当主goroutine退出时,程序终止,因此dispatcher()没有时间做任何事情。您需要封锁main()直到dispatcher()完成。通道可用于此目的:package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "os"&nbsp; &nbsp; "bufio")var done = make(chan bool)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// create channel// Load files and send them into a channel for mappers reading.func dispatcher(arr []string,channel chan string) {&nbsp; &nbsp; for _,path := range arr {&nbsp; &nbsp; &nbsp; &nbsp; file,err := os.Open(path)&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("begin to dispatch ", path)&nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(err)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; os.Exit(-1)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; defer file.Close()&nbsp; &nbsp; &nbsp; &nbsp; reader := bufio.NewReaderSize(file, 32*10*1024)&nbsp; &nbsp; &nbsp; &nbsp; i := 0&nbsp; &nbsp; &nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; line,_ := reader.ReadString('\n')&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; channel <- line&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i++&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if i%200 == 0 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(i," lines parsed")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("finish dispatch ", path)&nbsp; &nbsp; }&nbsp; &nbsp; done <- true&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// notify main() of completion}func main() {&nbsp; &nbsp; path := os.Args&nbsp; &nbsp; if len(path) < 2 {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Need Input Files")&nbsp; &nbsp; &nbsp; &nbsp; os.Exit(0)&nbsp; &nbsp; }&nbsp; &nbsp; channel := make(chan string)&nbsp; &nbsp; fmt.Println("before dispatcher")&nbsp; &nbsp; go dispatcher(path[1:],channel)&nbsp; &nbsp; <-done&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// wait for dispatcher()&nbsp; &nbsp; fmt.Println("after dispatcher")}

蝴蝶不菲

我修改了您的示例,使其在没有文件I / O的Go操场上运行;而是在频道上发送随机数。@Victor Deryagin的解释和他使用“完成”频道的建议是正确的。出现死锁的原因是您的goroutine在通道上发送,但没有人从该通道中读取数据,因此该程序此时被卡住。在上面的链接中,我添加了一个消费者goroutine。然后,程序将按预期并发运行。请注意,要等待几个goroutine,使用sync.WaitGroup会更清晰,更轻松。

萧十郎

在原始问题中需要解决两个问题。发送完所有数据后,您必须关闭通道。在func中laodData,请使用close(channel)发布所有数据。传递sync.Waitgroup作为参考。您将wg作为参数中的值发送给以下函数...laodData和调度程序函数。解决这两个问题将解决您的死锁问题。代码中出现死锁的原因如下:不关闭发送通道将导致下游通道等待更长的时间。发送参数sync.Waitgroupas作为值。应该将其作为参考发送,否则它将创建您要发送的对象的新副本。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go