package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
var wg sync.WaitGroup
//计算一个 64 位随机数的各位的和
func randNumber(x int64) int64 {
var sum int64 = 0
for x > 0 {
a := x % 10
x = x / 10
sum += a
}
return sum
}
func main() {
wg.Add(25)
var jobChan = make(chan int64, 10)
var resultChan = make(chan int64, 10)
go func(jobChan chan<- int64, ) {
defer wg.Done()
for i:=0;i<1000;i++{
rand.Seed(time.Now().UnixNano())
jobChan <- rand.Int63n(100)
}
}(jobChan)
for i:=0;i<24;i++{
go func(jobChan <-chan int64, resultChan chan<- int64, ) {
defer wg.Done()
for num:= range jobChan{
resultChan <- randNumber(num)
}
}(jobChan, resultChan)
}
for i:= range resultChan{
fmt.Println(i)
}
wg.Wait()
}
发生错误:fatal error: all goroutines are asleep - deadlock!
请教一下,为什么会发生死锁的情况?
1
linjunyi22 2020-06-02 17:20:09 +08:00
```go
package main import ( "fmt" "math/rand" "sync" "time" ) var wg sync.WaitGroup //计算一个 64 位随机数的各位的和 func randNumber(x int64) int64 { var sum int64 = 0 for x > 0 { a := x % 10 x = x / 10 sum += a } return sum } func main() { wg.Add(25) var jobChan = make(chan int64, 10) var resultChan = make(chan int64, 10) go func(jobChan chan<- int64, ) { defer wg.Done() for i := 0; i < 1000; i++ { rand.Seed(time.Now().UnixNano()) jobChan <- rand.Int63n(100) } close(jobChan) // 此处要关闭 jobChan,否则在 jobChan 的 range 遍历中会一直阻塞 }(jobChan) for i := 0; i < 24; i++ { go func(jobChan <-chan int64, resultChan chan<- int64, ) { defer wg.Done() for num := range jobChan { resultChan <- randNumber(num) } }(jobChan, resultChan) } // 此处 resultChan 的遍历放到一个 goroutine 中执行,让 wg 的 wait 执行完后主协程直接退出 // 如果放在主协程中,也没有关闭 resultChan 的话,也会造成阻塞,就会产生死锁 go func() { for i := range resultChan { fmt.Println(i) } }() wg.Wait() } ``` |
2
beidounanxizi 2020-06-02 17:21:04 +08:00
去看看 waitgroup 实现吧
|
3
evill 2020-06-02 17:36:57 +08:00
channel 没有关闭
for num:= range jobChan 永远不会退出 |
4
zjj19950716 2020-06-02 17:39:22 +08:00
for num:= range jobChan{
resultChan <- randNumber(num) } job 1000 个发完之后,这边还一直卡主。 最后的 Wait()也没意义,从 resultChan 读那里也退不出来 |
5
asAnotherJack 2020-06-02 17:41:24 +08:00
原因就是 2l 说的那样,因为 jobChan 和 resultChan 没有 close 阻塞在循环里了,jobChan 就像 2l 那样处理,resultChan 的处理,可以在 wg.Wait()后边 close resultChan,然后再 range resultChan 打印结果
|
6
liu826250634 OP @linjunyi22 感谢, 刚学习 go,有一些概念改搞不清。但是你这种方法好像会造成接收不完全就会退出。我自己也解决了这个问题了。
``` package main import ( "context" "fmt" "math/rand" "sync" "time" ) var ( wg = sync.WaitGroup{} // 用于计数, 让程序正常执行,不会主函数执行完子函数还没执行。计数清 0 则不用等待 a int //lock sync.Mutex rwlock sync.RWMutex icons map[string]string loadIconsOnce sync.Once //m sync.Map ) func randNumber(x int64) int64 { var sum int64 = 0 for x > 0 { a := x % 10 x = x / 10 sum += a } return sum } func main() { wg.Add(25) defer wg.Wait() var maxSend = 10 var jobChan = make(chan int64, 10) var resultChan = make(chan int64, 10) var lock sync.Mutex ctx, cancel := context.WithCancel(context.Background()) //var once sync.Once go func(jobChan chan<- int64, ) { for i:=0;i<maxSend;i++{ rand.Seed(time.Now().UnixNano()) jobChan <- rand.Int63n(100) } close(jobChan) wg.Done() }(jobChan) count1 := 1 for i:=0;i<24;i++{ go func(jobChan <-chan int64, resultChan chan int64, ctx context.Context) { defer wg.Done() for num:= range jobChan{ select { case <- ctx.Done(): return case resultChan <- randNumber(num): lock.Lock() fmt.Println("count:", count1) count1 += 1 lock.Unlock() } } }(jobChan, resultChan, ctx) } num := maxSend count := 1 for value := range resultChan { if num == 1 { fmt.Printf("key:%v, value:%v\n", count, value) cancel() return }else { num -= 1 fmt.Printf("key:%v, value:%v\n", count, value) count += 1 } } } ``` |
7
liu826250634 OP 回复中, 写代码怎么 md 不生效了= =
|