致命错误,所有的goroutine都处于休眠状态 – 死锁

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

fatal error all goroutines are asleep - deadlock

问题

我正在使用缓冲通道,并且我得到了我所需要的正确输出。

但是当我使用非缓冲通道时,我遇到了错误,错误信息是"fatal error: all goroutines are asleep - deadlock!"。为什么会发生这种情况,以及如何解决这个问题?

在使用缓冲通道时,你可以在创建通道时指定通道的容量,例如make(chan Expert, 3)。这意味着通道可以同时容纳多个元素,而不会阻塞发送方。当通道已满时,发送方会被阻塞,直到有空间可用。

而在使用非缓冲通道时,你只需要创建一个通道,例如make(chan Expert),它没有指定容量。这意味着发送方和接收方必须同时准备好,否则它们将彼此阻塞。这就是为什么你在使用非缓冲通道时遇到了死锁错误的原因。

要解决这个问题,你可以通过以下几种方式之一:

  1. 使用缓冲通道:如果你的发送方和接收方的速度不匹配,或者你希望发送方能够发送多个元素而不被阻塞,那么使用缓冲通道是一个不错的选择。

  2. 使用带有select语句的非阻塞发送和接收操作:你可以使用select语句来在发送和接收操作之间进行选择,以避免死锁。通过在select语句中使用default分支,你可以在通道没有准备好时执行其他操作。

  3. 使用sync.WaitGroup等待所有的goroutine完成:在你的代码中,你使用了sync.WaitGroup来等待所有的goroutine完成。确保你的goroutine都正确地调用了wg.Done()来通知WaitGroup,以避免死锁。

关于何时使用缓冲通道和非缓冲通道,你可以根据以下几个因素来判断:

  • 如果你的发送方和接收方的速度不匹配,或者你希望发送方能够发送多个元素而不被阻塞,那么使用缓冲通道是一个不错的选择。

  • 如果你需要确保发送方和接收方同时准备好,以避免数据丢失或死锁,那么使用非缓冲通道是更合适的。

  • 另外,你还可以根据具体的需求和性能要求来选择使用缓冲通道还是非缓冲通道。

英文:

I am using buffered channel and i get a proper output what i need.

package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup

type Expert struct {
	name string
	age  int
}

func main() {
	fmt.Println("==== GoRoutines ====")
	expertChannel := make(chan Expert, 3)
	wg.Add(1)
	go printHello()
	wg.Add(1)
	go addDataToChannel(expertChannel, "Name", 24)
	wg.Add(1)
	go addDataToChannel(expertChannel, "Name", 24)
	wg.Add(1)
	go addDataToChannel(expertChannel, "Name", 24)
	wg.Wait()
	close(expertChannel)
	for x := range expertChannel {
		fmt.Println("Expert Data :: ", x)
	}

}

func printHello() {
	for i := 1; i <= 5; i++ {
		fmt.Println("This is from PrintHello() Function where i = ", i)
	}
	defer wg.Done()

}

func addDataToChannel(c chan Expert, name string, age int) {
	defer wg.Done()

	c <- Expert{
		name,
		age,
	}
}

But when i am using unBuffered channel then i am getting error and that is
fatal error: all goroutines are asleep - deadlock!
why this happen and how to resolve this?

package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup

type Expert struct {
	name string
	age  int
}

func main() {
	fmt.Println("==== GoRoutines ====")
	expertChannel := make(chan Expert)
	wg.Add(1)
	go printHello()
	wg.Add(1)
	go addDataToChannel(expertChannel, "Name", 24)
	wg.Add(1)
	go addDataToChannel(expertChannel, "Name", 24)
	wg.Add(1)
	go addDataToChannel(expertChannel, "Name", 24)
	wg.Wait()
	close(expertChannel)
	for x := range expertChannel {
		fmt.Println("Expert Data :: ", x)
	}

}

func printHello() {
	for i := 1; i <= 5; i++ {
		fmt.Println("This is from PrintHello() Function where i = ", i)
	}
	defer wg.Done()

}

func addDataToChannel(c chan Expert, name string, age int) {
	defer wg.Done()

	c <- Expert{
		name,
		age,
	}
}

when we will use buffered channel and when will use unbuffered channel how to identify the use case of both channel category?

答案1

得分: 1

如果缓冲区已满,通过通道发送和接收操作将会阻塞。对于无缓冲通道来说,除非数据在另一端被读取,否则它会立即阻塞。

一旦你向通道发送了第一个数据,除非你进行读取,否则其他例程将无法向通道发送数据。因此,发送者会被阻塞。

你需要解除阻塞从通道读取的主例程,这样发送者才能找到继续向通道发送数据的空间。

目前,wg.Wait()是阻塞的,不允许主例程(for循环)从通道中读取数据。一旦它开始从通道中读取数据,被阻塞的发送者也可以恢复,并继续发送数据。

在一个并发的go例程中执行wg.Wait():

go func() {
	wg.Wait()
	close(expertChannel)
}()
英文:

Send and receive over a channel are blocking if buffer is full. And for unbuffered channel since it has no buffer unless the data is read at the other end it will block immediately.

Once you send first data to channel, unless you read there is no space for other routines to send data to channel. So the senders are blocked.

You need to unblock the main routine that is reading from the channel. So that the senders will find space to continue sending data to channel.

Right now wg.Wait() is blocking and not allowing the main routine (for loop) to read from channel. Once it starts reading from channel the blocked senders can also resume and can send further data.

Do wg.Wait() in a concurrent go routine:

go func() {
	wg.Wait()
	close(expertChannel)
}()

huangapple
  • 本文由 发表于 2021年5月18日 15:00:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/67581390.html
匿名

发表评论

匿名网友

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

确定