英文:
Deadlock while using goroutines
问题
我有一个程序,它有两个功能:
- 读取日志条目并创建
logEntry
对象 - 处理每个
logEntry
实例
在这里,读取操作由单独的goroutine完成,而对所有读取的条目进行处理的操作由单个goroutine完成。
我使用了一个waitgroup - wg
来确保在程序退出之前读取所有的日志条目,并使用一个信号通道 - done
来确保日志条目的处理完成。
waitgroup按预期工作,但是当我调用<-done
来确保程序在读取日志文件处理完成后退出时,它会抛出错误fatal error: all goroutines are asleep - deadlock!
。
有人能解释一下为什么会发生这种情况,以及如何修复上述错误吗?
main.go:
package main
import (
"fmt"
"sync"
"time"
)
type logEntry struct {
lines []string
created_at string
line_count int
}
var wg sync.WaitGroup
func main() {
linesChan := make(chan (logEntry))
done := make(chan (bool), 1)
// 处理来自lines的条目
go func() {
for c := range linesChan {
time.Sleep(100 * time.Millisecond)
fmt.Printf("%v\n", c)
}
done <- true
}()
// 读取条目
for i := 1; i <= 10; i++ {
wg.Add(1)
go func(i int, linesChan chan (logEntry)) {
read(i, linesChan)
}(i, linesChan)
}
// 等待所有文件都被读取
wg.Wait()
// 等待所有日志条目都被处理
<-done
close(done)
}
func read(count int, channel chan (logEntry)) {
fmt.Println(count, "read")
channel <- logEntry{
line_count: count,
}
wg.Done()
}
输出:
10 read
6 read
3 read
1 read
4 read
8 read
7 read
2 read
5 read
9 read
{[] 10}
{[] 6}
{[] 3}
{[] 1}
{[] 4}
{[] 8}
{[] 7}
{[] 2}
{[] 5}
{[] 9}
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
.../main.go:44 +0x13a
goroutine 18 [chan receive]:
main.main.func1()
.../main.go:24 +0x145
created by main.main
.../main.go:23 +0x9d
exit status 2
英文:
I have a program which does 2 things:
- Read log entries and create
logEntry
objects - Process each
logEntry
instances
Here, reading is done by separate goroutines and processing of all the read entries is done by a single goroutine.
I'm using a waitgroup - wg
to ensure that all the log entries are read before the program quits and a signal channel - done
to ensure the processing of the log entries are completed.
The waitgroup is working as expected, however when I call <-done
to ensure that the program exits only after the read log files are processed, it throws the error fatal error: all goroutines are asleep - deadlock!
.
Could someone please explain why this is happening and how to fix the above error?
main.go:
package main
import (
"fmt"
"sync"
"time"
)
type logEntry struct {
lines []string
created_at string
line_count int
}
var wg sync.WaitGroup
func main() {
linesChan := make(chan (logEntry))
done := make(chan (bool), 1)
// Process entries from lines
go func() {
for c := range linesChan {
time.Sleep(100 * time.Millisecond)
fmt.Printf("%v\n", c)
}
done <- true
}()
// Read lines
for i := 1; i <= 10; i++ {
wg.Add(1)
go func(i int, linesChan chan (logEntry)) {
read(i, linesChan)
}(i, linesChan)
}
// Wait till all the files are read
wg.Wait()
// Wait till all the log entries are processed
<-done
close(done)
}
func read(count int, channel chan (logEntry)) {
fmt.Println(count, "read")
channel <- logEntry{
line_count: count,
}
wg.Done()
}
Output:
10 read
6 read
3 read
1 read
4 read
8 read
7 read
2 read
5 read
9 read
{[] 10}
{[] 6}
{[] 3}
{[] 1}
{[] 4}
{[] 8}
{[] 7}
{[] 2}
{[] 5}
{[] 9}
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
.../main.go:44 +0x13a
goroutine 18 [chan receive]:
main.main.func1()
.../main.go:24 +0x145
created by main.main
.../main.go:23 +0x9d
exit status 2
答案1
得分: 2
在你的代码中,你监听了linesChan
通道,但没有关闭它。当所有数据传递完毕时,你需要关闭这个通道。done <- true
不会被执行。
但在这里不需要使用通道进行同步,sync.WaitGroup{}
就足够了。
package main
import (
"fmt"
"sync"
"time"
)
type logEntry struct {
lines []string
created_at string
line_count int
}
var wg sync.WaitGroup
func main() {
linesChan := make(chan logEntry)
// 处理来自lines的条目
go func() {
for c := range linesChan {
time.Sleep(100 * time.Millisecond)
fmt.Printf("%v\n", c)
}
}()
// 读取行
for i := 1; i <= 10; i++ {
wg.Add(1)
go func(i int, linesChan chan logEntry) {
read(i, linesChan)
}(i, linesChan)
}
// 等待所有文件都被读取完毕
wg.Wait()
}
func read(count int, channel chan logEntry) {
fmt.Println(count, "read")
channel <- logEntry{
line_count: count,
}
wg.Done()
}
英文:
in your case you are listening for linesChan
, but not close it. You need to close this channel, when all data will be passed. done <- true
won't be executed.
But don't need channel for sync here, sync.WaitGroup{}
will be enough.
package main
import (
"fmt"
"sync"
"time"
)
type logEntry struct {
lines []string
created_at string
line_count int
}
var wg sync.WaitGroup
func main() {
linesChan := make(chan (logEntry))
// Process entries from lines
go func() {
for c := range linesChan {
time.Sleep(100 * time.Millisecond)
fmt.Printf("%v\n", c)
}
}()
// Read lines
for i := 1; i <= 10; i++ {
wg.Add(1)
go func(i int, linesChan chan (logEntry)) {
read(i, linesChan)
}(i, linesChan)
}
// Wait till all the files are read
wg.Wait()
}
func read(count int, channel chan (logEntry)) {
fmt.Println(count, "read")
channel <- logEntry{
line_count: count,
}
wg.Done()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论