为了账号安全,请及时绑定邮箱和手机立即绑定

Golang Goroutine不在通道内部运行

Golang Goroutine不在通道内部运行

Go
慕少森 2021-05-14 19:12:42
我正在尝试实现字数统计程序,但是第一步我遇到了一些问题。这是我的代码:package mainimport (    "fmt"    "os"    "bufio"    "sync")// Load data into channelfunc 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 mappersfunc 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.txtthrow: all goroutines are asleep - deadlock!goroutine 1 [semacquire]:sync.runtime_Semacquire(0x42154100, 0x42154100)    /usr/local/go/src/pkg/runtime/zsema_amd64.c:146 +0x25sync.(*WaitGroup).Wait(0x4213b440, 0x0)    /usr/local/go/src/pkg/sync/waitgroup.go:79 +0xf2main.main()    /Users/kuankuan/go/src/mreasy/main.go:66 +0x238
查看完整描述

3 回答

?
白衣非少年

TA贡献1155条经验 获得超0个赞

当主goroutine退出时,程序终止,因此dispatcher()没有时间做任何事情。您需要封锁main()直到dispatcher()完成。通道可用于此目的:


package main


import (

    "fmt"

    "os"

    "bufio"

)


var done = make(chan bool)             // create channel


// Load files and send them into a channel for mappers reading.

func dispatcher(arr []string,channel chan string) {

    for _,path := range arr {

        file,err := os.Open(path)

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

        if err != nil {

            fmt.Println(err)

            os.Exit(-1)

        }

        defer file.Close()

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

        i := 0

        for {

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

            channel <- line

            i++

            if i%200 == 0 {

                fmt.Println(i," lines parsed")

            }

        }

        fmt.Println("finish dispatch ", path)

    }

    done <- true                 // notify main() of completion

}


func main() {

    path := os.Args

    if len(path) < 2 {

        fmt.Println("Need Input Files")

        os.Exit(0)

    }

    channel := make(chan string)

    fmt.Println("before dispatcher")

    go dispatcher(path[1:],channel)

    <-done                 // wait for dispatcher()

    fmt.Println("after dispatcher")

}



查看完整回答
反对 回复 2021-05-24
?
蝴蝶不菲

TA贡献1810条经验 获得超4个赞

修改了您的示例,使其在没有文件I / O的Go操场上运行;而是在频道上发送随机数。

@Victor Deryagin的解释和他使用“完成”频道的建议是正确的。出现死锁的原因是您的goroutine在通道上发送,但没有人从该通道中读取数据,因此该程序此时被卡住。在上面的链接中,我添加了一个消费者goroutine。然后,程序将按预期并发运行。

请注意,要等待几个goroutine,使用sync.WaitGroup会更清晰,更轻松。


查看完整回答
反对 回复 2021-05-24
?
萧十郎

TA贡献1815条经验 获得超13个赞

在原始问题中需要解决两个问题。

  1. 发送完所有数据后,您必须关闭通道。在func中laodData,请使用close(channel)发布所有数据。

  2. 传递sync.Waitgroup作为参考。您将wg作为参数中的值发送给以下函数...laodData和调度程序函数。

解决这两个问题将解决您的死锁问题。代码中出现死锁的原因如下:

  • 不关闭发送通道将导致下游通道等待更长的时间。

  • 发送参数sync.Waitgroupas作为值。应该将其作为参考发送,否则它将创建您要发送的对象的新副本。


查看完整回答
反对 回复 2021-05-24
  • 3 回答
  • 0 关注
  • 225 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信