go 发生死锁的问题

liu826250634 4月前 63

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!
请教一下,为什么会发生死锁的情况?
最新回复 (7)
  • linjunyi22 4月前
    引用 2
    ```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()
    }
    ```
  • beidounanxizi 4月前
    引用 3
    去看看 waitgroup 实现吧
  • evill 4月前
    引用 4
    channel 没有关闭
    for num:= range jobChan
    永远不会退出
  • zjj19950716 4月前
    引用 5
    for num:= range jobChan{
    resultChan <- randNumber(num)
    }
    job 1000 个发完之后,这边还一直卡主。
    最后的 Wait()也没意义,从 resultChan 读那里也退不出来
  • asAnotherJack 4月前
    引用 6
    原因就是 2l 说的那样,因为 jobChan 和 resultChan 没有 close 阻塞在循环里了,jobChan 就像 2l 那样处理,resultChan 的处理,可以在 wg.Wait()后边 close resultChan,然后再 range resultChan 打印结果
  • 楼主 liu826250634 4月前
    引用 7
    @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
    }
    }
    }

    ```
  • 楼主 liu826250634 4月前
    引用 8
    回复中, 写代码怎么 md 不生效了= =
  • 游客
    9
返回