英文:
GOLANG: Learning goroutine took me to a deadlock
问题
我是一个GO的新手,我正在努力弄清楚goroutines是如何工作以及如何同步它们。
这是我写的一个简单程序,用来学习它们的一些知识:
package main
import (
"fmt"
"sync"
"time"
)
func printAfterDelay(delay time.Duration, message string, wg *sync.WaitGroup) {
time.Sleep(delay)
fmt.Println(message)
wg.Done()
}
func add(a int, b int, chan1 chan int, wg *sync.WaitGroup) {
c := a + b
chan1 <- c
//close(chan1)
wg.Done()
}
func printer(chan1 chan int, wg *sync.WaitGroup) {
for result := range chan1 {
//result := <-chan1
//time.Sleep(2000 * time.Millisecond)
fmt.Println(result)
}
close(chan1)
wg.Done()
}
func main() {
//var wg sync.WaitGroup
wg := &sync.WaitGroup{}
fmt.Println("Start...")
wg.Add(1)
go printAfterDelay(2000*time.Millisecond, "Try", wg)
chan1 := make(chan int)
wg.Add(1)
go add(5, 4, chan1, wg)
wg.Add(1)
go add(3, 1, chan1, wg)
wg.Add(1)
go printer(chan1, wg)
//time.Sleep(3000 * time.Millisecond)
wg.Wait()
fmt.Println("End")
}
add函数接受两个整数,将它们相加并将结果传递给一个通道(chan)。
printer函数从通道中获取结果并打印它们。
这两个函数在main()中作为goroutines调用,所以我还传递了一个WaitGroup作为指针,在调用goroutines之前增加它,在函数结束时减少它。
无论如何,当我执行编译后的程序时,它打印出:
Start...
9
4
Try
fatal error: all goroutines are asleep - deadlock!
goroutine 16 [semacquire]:
sync.runtime_Semacquire(0x18334008)
/usr/lib/go/src/pkg/runtime/sema.goc:199 +0x37
sync.(*WaitGroup).Wait(0x183240e0)
/usr/lib/go/src/pkg/sync/waitgroup.go:129 +0x12d
main.main()
/home/ettore/go/src/example/goroutine/main.go:52 +0x1e5
goroutine 19 [finalizer wait]:
runtime.park(0x80599e0, 0x814f000, 0x814e3e9)
/usr/lib/go/src/pkg/runtime/proc.c:1369 +0x94
runtime.parkunlock(0x814f000, 0x814e3e9)
/usr/lib/go/src/pkg/runtime/proc.c:1385 +0x3
frunfinq()
/usr/lib/go/src/pkg/runtime/mgc0.c:2644 +0xc5
runtime.goexit()
/usr/lib/go/src/pkg/runtime/proc.c:1445
goroutine 23 [chan receive]:
main.printer(0x1831a090, 0x183240e0)
/home/ettore/go/src/example/goroutine/main.go:23 +0x46
created by main.main
/home/ettore/go/src/example/goroutine/main.go:49 +0x1d7
问题出在哪里?有什么问题吗?
谢谢!
英文:
I'm a GO newbie and I'm trying to figure out how does goroutines work and how to synchronize them.
This is a simple program I wrote to learn something about them:
package main
import (
"fmt"
"sync"
"time"
)
func printAfterDelay(delay time.Duration, message string, wg *sync.WaitGroup) {
time.Sleep(delay)
fmt.Println(message)
wg.Done()
}
func add(a int, b int, chan1 chan int, wg *sync.WaitGroup) {
c := a + b
chan1 <- c
//close(chan1)
wg.Done()
}
func printer(chan1 chan int, wg *sync.WaitGroup) {
for result := range chan1 {
//result := <-chan1
//time.Sleep(2000 * time.Millisecond)
fmt.Println(result)
}
close(chan1)
wg.Done()
}
func main() {
//var wg sync.WaitGroup
wg := &sync.WaitGroup{}
fmt.Println("Start...")
wg.Add(1)
go printAfterDelay(2000*time.Millisecond, "Try", wg)
chan1 := make(chan int)
wg.Add(1)
go add(5, 4, chan1, wg)
wg.Add(1)
go add(3, 1, chan1, wg)
wg.Add(1)
go printer(chan1, wg)
//time.Sleep(3000 * time.Millisecond)
wg.Wait()
fmt.Println("End")
}
The add function takes two int, sums them and pass the result to a chan.
The printer function takes the results from the chan and print them.
The two funtions are called in main() as goroutines, so i also passed a WaitGroup as a pointer, that is incremented before calling the goroutines and decremented when the functions end.
Anyway when I execute the compiled program it prints:
Start...
9
4
Try
fatal error: all goroutines are asleep - deadlock!
goroutine 16 [semacquire]:
sync.runtime_Semacquire(0x18334008)
/usr/lib/go/src/pkg/runtime/sema.goc:199 +0x37
sync.(*WaitGroup).Wait(0x183240e0)
/usr/lib/go/src/pkg/sync/waitgroup.go:129 +0x12d
main.main()
/home/ettore/go/src/example/goroutine/main.go:52 +0x1e5
goroutine 19 [finalizer wait]:
runtime.park(0x80599e0, 0x814f000, 0x814e3e9)
/usr/lib/go/src/pkg/runtime/proc.c:1369 +0x94
runtime.parkunlock(0x814f000, 0x814e3e9)
/usr/lib/go/src/pkg/runtime/proc.c:1385 +0x3
frunfinq()
/usr/lib/go/src/pkg/runtime/mgc0.c:2644 +0xc5
runtime.goexit()
/usr/lib/go/src/pkg/runtime/proc.c:1445
goroutine 23 [chan receive]:
main.printer(0x1831a090, 0x183240e0)
/home/ettore/go/src/example/goroutine/main.go:23 +0x46
created by main.main
/home/ettore/go/src/example/goroutine/main.go:49 +0x1d7
Where and what is the problem(s)?
Thanks!
答案1
得分: 1
以下是翻译好的内容:
以下代码是有效的。我的意思是它不会发生死锁。
由于将打印函数放在通道的范围循环中,它会在通道关闭后自动停止。我在最后附近添加了3秒的延迟,以便try循环有足够的时间打印。不过,建议阅读文档,它会解释这些细节的100%。
package main
import (
"fmt"
"sync"
"time"
)
func printAfterDelay(delay time.Duration, message string, wg *sync.WaitGroup) {
time.Sleep(delay)
fmt.Println(message)
}
func add(a int, b int, chan1 chan int, wg *sync.WaitGroup) {
c := a + b
chan1 <- c
wg.Done()
}
func printer(chan1 chan int, wg *sync.WaitGroup) {
for result := range chan1 {
fmt.Println(result)
}
}
func main() {
//var wg sync.WaitGroup
wg := &sync.WaitGroup{}
fmt.Println("Start...")
go printAfterDelay(2000*time.Millisecond, "Try", wg)
chan1 := make(chan int)
wg.Add(1)
go add(5, 4, chan1, wg)
wg.Add(1)
go add(3, 1, chan1, wg)
go printer(chan1, wg)
time.Sleep(3000 * time.Millisecond)
wg.Wait()
close(chan1)
fmt.Println("End")
}
英文:
The following works. By that I mean that it doesn't deadlock.
Since you have the printer function in a range loop over the channel, it'll automatically stop after the channel is closed. I added the 3 sec delay near the end to give the try loop time to print. Read the documentation though. It'll explain 100% of these details.
package main
import (
"fmt"
"sync"
"time"
)
func printAfterDelay(delay time.Duration, message string, wg *sync.WaitGroup) {
time.Sleep(delay)
fmt.Println(message)
}
func add(a int, b int, chan1 chan int, wg *sync.WaitGroup) {
c := a + b
chan1 <- c
wg.Done()
}
func printer(chan1 chan int, wg *sync.WaitGroup) {
for result := range chan1 {
fmt.Println(result)
}
}
func main() {
//var wg sync.WaitGroup
wg := &sync.WaitGroup{}
fmt.Println("Start...")
go printAfterDelay(2000*time.Millisecond, "Try", wg)
chan1 := make(chan int)
wg.Add(1)
go add(5, 4, chan1, wg)
wg.Add(1)
go add(3, 1, chan1, wg)
go printer(chan1, wg)
time.Sleep(3000 * time.Millisecond)
wg.Wait()
close(chan1)
fmt.Println("End")
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论