Golang goroutine不';不要在通道内运行

Golang goroutine不';不要在通道内运行,go,Go,我正试图实现一个字数计算程序,但第一步我遇到了一些问题 这是我的密码: 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

我正试图实现一个字数计算程序,但第一步我遇到了一些问题

这是我的密码:

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")
}

谢谢

程序在主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")
}
主程序包
进口(
“fmt”
“操作系统”
“布菲奥”
)
var done=make(chan bool)//创建通道
//加载文件并将其发送到通道中,以便映射程序读取。
func调度程序(arr[]字符串,通道chan字符串){
对于u,路径:=范围arr{
文件,错误:=os.Open(路径)
fmt.Println(“开始调度”,路径)
如果错误!=零{
fmt.Println(错误)
操作系统退出(-1)
}
延迟文件。关闭()
reader:=bufio.NewReaderSize(文件,32*10*1024)
i:=0
为了{
第行,u:=reader.ReadString('\n')
通道I在没有文件I/O的Go操场上运行;它在通道上发送随机数

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


请注意,要等待几个goroutine,它更清晰、更易于使用。

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

  • 发送完所有数据后,必须关闭频道。在func
    laodData
    中,请使用close(channel)post发送所有数据
  • sync.Waitgroup
    作为引用传递。您正在将wg作为参数中的值发送给以下函数…
    laodData
    和dispatcher函数
  • 解决这两个问题将解决死锁问题。代码中出现死锁的原因如下:

    • 不关闭发送通道将导致下游通道等待较长时间
    • sync.Waitgroup
      的参数作为值发送。应将其作为引用发送,否则将创建所发送对象的新副本

    在这种情况下,在
    go dispatcher(路径[1:],通道)
    中删除
    go
    会更简单。谢谢@dystory,我需要在主线程中的dispatcher之外做些其他事情。嗨,维克托,我听从了你的建议,但我遇到了死锁!问题。**抛出:所有Goroutine都处于休眠状态-死锁!通道@MrROY
    dispatcher()
    将内容发送到一个
    频道
    ,作为参数传递,另一端没有人接受它,因此它的goroutine被阻止。
    main()
    也被阻止,因为它正在等待
    dispatcher()
    完成。嗨,@VictorYagin感谢你的伟大的anwser,但我给频道添加了一个接收器,它仍然死锁。
    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")
    }