Golang使用了WaitGroup,但仍然出现了死锁错误。

huangapple go评论163阅读模式
英文:

golang used waitGroup and still ended up with a deadlock error

问题

我正在尝试按照《Go并发编程》一书中的示例实现桥接模式。

func bridge_impl() {
    done := make(chan interface{})
    defer close(done)
    var wg sync.WaitGroup
    bridge := func(
        done <-chan interface{},
        chanStream <-chan <-chan interface{},
    ) <-chan interface{} {
        valStream := make(chan interface{})
        go func() {
            wg.Add(1)
            defer close(valStream)
            for {
                var stream <-chan interface{}
                select {
                case maybeStream, ok := <-chanStream:
                    fmt.Println("works")
                    if ok == false {
                        return
                    }
                    stream = maybeStream
                case <-done:
                    return
                }
                for val := range stream {
                    select {
                    case valStream <- val:
                    case <-done:
                    }
                }
            }
        }()
        return valStream
    }
    genVals := func() <-chan <-chan interface{} {
        chanStream := make(chan (<-chan interface{}))
        go func() {
            wg.Add(1)
            defer close(chanStream)
            for i := 0; i < 10; i++ {
                stream := make(chan interface{})
                stream <- i
                close(stream)
                chanStream <- stream
            }
        }()
        return chanStream
    }
    for v := range bridge(done, genVals()) {
        fmt.Printf("%v ", v)
    }
    wg.Wait()
}

然而,我遇到了一个死锁错误all goroutines are asleep - deadlock!。起初,我认为即使在书中的示例中没有实现,我也应该添加一个WaitGroup,但结果仍然出现了相同的错误。

英文:

I'm trying to implement the bridge pattern following Go Concurrency book

func bridge_impl() {
	done := make(chan interface{})
	defer close(done)
	var wg sync.WaitGroup
	bridge := func(
		done &lt;-chan interface{},
		chanStream &lt;-chan &lt;-chan interface{},
	) &lt;-chan interface{} {
		valStream := make(chan interface{})
		go func() {
			wg.Add(1)
			defer close(valStream)
			for {
				var stream &lt;-chan interface{}
				select {
				case maybeStream, ok := &lt;-chanStream:
					fmt.Println(&quot;works&quot;)
					if ok == false {
						return
					}
					stream = maybeStream
				case &lt;-done:
					return
				}
				for val := range stream {
					select {
					case valStream &lt;- val:
					case &lt;-done:
					}
				}
			}
		}()
		return valStream
	}
	genVals := func() &lt;-chan &lt;-chan interface{} {
		chanStream := make(chan (&lt;-chan interface{}))
		go func() {
			wg.Add(1)
			defer close(chanStream)
			for i := 0; i &lt; 10; i++ {
				stream := make(chan interface{})
				stream &lt;- i
				close(stream)
				chanStream &lt;- stream
			}
		}()
		return chanStream
	}
	for v := range bridge(done, genVals()) {
		fmt.Printf(&quot;%v &quot;, v)
	}
	wg.Wait()
}

However I'm receiving a deadlock errorall goroutines are asleep - deadlock! at first I thought I should add a waitgroup even though it wasn't implemented in the book example but I ended up with the same error

答案1

得分: 2

有两个主要问题。

第一个问题

for i := 0; i < 10; i++ {
	stream := make(chan interface{})
	stream <- i
	close(stream)
	chanStream <- stream
}

在创建后向无缓冲通道写入数据,但没有 goroutine 读取。请使用带缓冲的通道或另一个 goroutine。

stream := make(chan interface{}, 1) // 缓冲大小为 1,以避免 `stream <- i` 阻塞

第二个问题
在使用 wg.Add(1) 时没有使用 wg.Done()。你可以在两种情况下都使用 defer

wg.Add(1)
defer wg.Done()
英文:

There are two main issues.
Working example

First issue:

for i := 0; i &lt; 10; i++ {
	stream := make(chan interface{})
	stream &lt;- i
	close(stream)
	chanStream &lt;- stream
}

writing to unbuffered channel after creation with no goroutine reading. Use buffered channel or another goroutine.

stream := make(chan interface{}, 1) // buffer size 1 to not block `stream &lt;- i`

Second issue:
Using wg.Add(1) without wg.Done().
You can use defer in both cases.

wg.Add(1)
defer wg.Done()

答案2

得分: 2

根据我理解,你根本不需要使用WaitGroup,只需要重新排列genVals函数循环中的语句顺序即可:

for i := 0; i < 10; i++ {
	stream := make(chan interface{})
	chanStream <- stream
	stream <- i
	close(stream)
}

你可以在以下链接中查看代码示例:https://go.dev/play/p/7D9OzrsvZyi

英文:

From what I understand you do not need a WaitGroup at all, you just need to re-order the statements in the genVals function's loop:

for i := 0; i &lt; 10; i++ {
	stream := make(chan interface{})
	chanStream &lt;- stream
	stream &lt;- i
	close(stream)
}

https://go.dev/play/p/7D9OzrsvZyi

huangapple
  • 本文由 发表于 2022年3月17日 20:47:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/71512541.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定