发送超过8个元素到一个通道是否会导致死锁?

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

Do sending more than 8 element to a channel can result in deadlock?

问题

package main

import (
	"fmt"
	"time"
)

func printCount(c chan int) {
	num := 0
	for num >= 0 {
		num = <-c
		fmt.Print(num, " ")
	}
}

func main() {
	a := []int{8, 6, 7, 5, 3, 0, 9, -1, 3, 4}
	// 如果我使用 a := []int{8, 6, 7, 5, 3, 0, 9, -1},那么程序就能正常工作

	c := make(chan int)

	go printCount(c)

	for _, v := range a {
		c <- v
	}

	time.Sleep(time.Second * 1)
	fmt.Println("主函数结束")
}

我尝试使用Go语言将切片的元素发送到通道,并打印出来。现在,当切片的元素数量达到8个时,程序能正常工作。但是,当我添加第9个元素时,会出现死锁的情况,我不知道为什么。我尝试使用waitgroup来解决这个问题,但仍然无法正常工作。

英文:
package main

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

func printCount(c chan int) {
	num := 0
	for num &gt;= 0 {
		num = &lt;-c
		fmt.Print(num, &quot; &quot;)

	}
}

func main() {

	a := []int{8, 6, 7, 5, 3, 0, 9, -1, 3, 4}
	// If i use a := []int{8, 6, 7, 5, 3, 0, 9, -1} then it works fine

	c := make(chan int)

	go printCount(c)

	for _, v := range a {

		c &lt;- v

	}

	time.Sleep(time.Second * 1)
	fmt.Println(&quot;End of main&quot;)
}

I try to send element of the slice to the channel and print it using golang.
Now upto 8 element the program works fine.
As i am adding 9th element in slice then deadlock conditions occures dont know why. I used to solve that by using the waitgroup but still not working.

答案1

得分: 1

通过(无缓冲的)通道发送一个值总是阻塞的,直到它在其他地方被接收。

我认为你在这里的意图是发送所有的值,然后只在它们大于或等于0时打印它们?你可以像这样修改你的printCount函数:

func printCount(c chan int) {
    for num := range c {
        if num >= 0 {
            fmt.Print(num, " ")
        }
    }
}

https://goplay.space/#m5eT9AYDH-Q

英文:

Sending a value through an (unbuffered) channel is always blocking, until it is received somewhere else.

I think your intention here is to send all values and then only print them if they are 0 or greater? You could alter your printCount like this:

func printCount(c chan int) {
    for num := range c {
        if num &gt;= 0 {
            fmt.Print(num, &quot; &quot;)
        }
    }
}

https://goplay.space/#m5eT9AYDH-Q

答案2

得分: 0

你好,只需将c := make(chan int)更改为c := make(chan int, 100),其中100是通道的最大容量:

package main
import (
	"fmt"
	"time"
)
func printCount(c chan int) {
	num := 0
	for num >= 0 {
		num = <-c
		fmt.Print(num, " ")
	}
}
func main() {
	a := []int{8, 6, 7, 5, 3, 0, 9, -1, 3, 4}
	// 如果我使用 a := []int{8, 6, 7, 5, 3, 0, 9, -1},那么它可以正常工作
	c := make(chan int, 40)
	go printCount(c)
	for _, v := range a {
		c <- v
	}
	time.Sleep(time.Second * 1)
	fmt.Println("End of main")
}

结果:

8 6 7 5 3 0 9 -1 End of main

英文:

Hi just change c := make(chan int) to c := make(chan int, 100)
where 100 is highest capacity of your channel:

package main
import (
	&quot;fmt&quot;
	&quot;time&quot;
)
func printCount(c chan int) {
	num := 0
	for num &gt;= 0 {
		num = &lt;-c
		fmt.Print(num, &quot; &quot;)
	}
}
func main() {
	a := []int{8, 6, 7, 5, 3, 0, 9, -1, 3, 4}
	// If i use a := []int{8, 6, 7, 5, 3, 0, 9, -1} then it works fine
	c := make(chan int, 40)
	go printCount(c)
	for _, v := range a {
		c &lt;- v
	}
	time.Sleep(time.Second * 1)
	fmt.Println(&quot;End of main&quot;)
}

result:

8 6 7 5 3 0 9 -1 End of main

答案3

得分: 0

printCount goroutine在处理负值时会退出。更准确地说,值-1会停止它。

在这里,printCount goroutine是唯一可以读取通道值的goroutine。当这个goroutine退出时,通道中就无法再写入值,因为该通道是无缓冲的

注意:该通道是无缓冲的,因此不能包含任何值。无缓冲通道是Go语言中一种将值从一个goroutine安全地传递给另一个goroutine的同步方式。

解决方案

你应该读取通道,直到不再需要处理更多元素。

不再需要使用time.Sleep(time.Second * 1)printCount现在会阻塞主goroutine直到完成!

package main

import (
    "fmt"
    "time"
)

func printCount(c chan int) {
    // 如果通道为空(或无缓冲)且已关闭,则退出。
    for num := range c {
        if num >= 0 {
            fmt.Print(num, " ")
        }
    }
}

func main() {

    a := []int{8, 6, 7, 5, 3, 0, 9, -1, 3, 4}

    c := make(chan int)

    go func(){
        // 在发送最后一个值后关闭通道
        defer close(c)

        for _, v := range a {
            c <- v
        }
    }()

    printCount(c)

    fmt.Println("主函数结束")
}
英文:

The printCount goroutine exits if a negative value is processed.
More precisely, the value -1 is stopping it.

Here the printCount goroutine is the only goroutine that can read the channel values. When this goroutine exits no more writing are possible in the channel because the channel is unbuffered.

NB: The channel is unbuffered and thus cannot contains any value. A unbuffered channel is a golang idiom to concurrently safe pass values from a goroutine to another synchronously.

Solution

You should read the channel until no more element need to be processed.

No more need to use time.Sleep(time.Second * 1), the printCount is now blocking the main goroutine until finished !



package main

import (
    &quot;fmt&quot;
    &quot;time&quot;
)

func printCount(c chan int) {
    // exits if the channel is empty (or unbuffered) and closed.
    for num := range c {
        if num &gt;= 0 {
            fmt.Print(num, &quot; &quot;)
        }
    }
}

func main() {

    a := []int{8, 6, 7, 5, 3, 0, 9, -1, 3, 4}

    c := make(chan int)

    go func(){
        // close the channel after sending the last value
        defer close(c)

        for _, v := range a {

            c &lt;- v

        }
    }()


    printCount(c)

    fmt.Println(&quot;End of main&quot;)
}

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

发表评论

匿名网友

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

确定