我正在尝试实施字数统计程序,但第一步我遇到了一些问题。
这是我的代码:
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
goroutine 2 [syscall]:
created by runtime.main
/usr/local/go/src/pkg/runtime/proc.c:221
goroutine 4 [chan receive]:
main.dispatcher(0x42115a50, 0x0, 0x2, 0x0)
/Users/kuankuan/go/src/mreasy/main.go:45 +0x223
created by main.main
/Users/kuankuan/go/src/mreasy/main.go:65 +0x228
exit status 2
谢谢!
答案 0 :(得分:8)
程序在主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")
}
答案 1 :(得分:2)
I modified your example在Go操场上运行,那里没有文件I / O;它会在频道上发送随机数字。
@Victor Deryagin的解释和他使用“完成”频道的建议是正确的。你遇到死锁的原因是你的goroutine在频道上发送,但没有人从中读取,所以程序在这一点上被卡住了。在上面的链接中,我添加了一个消费者goroutine。然后该程序按预期同时运行。
请注意,要等待几个goroutines,使用sync.WaitGroup会更清晰,更容易。
答案 2 :(得分:1)
原始问题需要解决两个问题。
laodData
中,请使用close(频道)帖子发送所有数据。sync.Waitgroup
作为参考。您将wg作为参数中的值发送给以下函数... laodData
和调度程序函数。修复这两个问题将解决您的死锁问题。代码中出现死锁的原因如下:
sync.Waitgroup
的参数作为值发送。它应该作为参考发送,否则它将创建您要发送的对象的新副本。