当填充通道的函数调用未嵌入Goroutine中时,会出现死锁的原因是因为通道的发送和接收操作是阻塞的。如果在主Goroutine中调用填充通道的函数,并且该函数内部没有将填充操作放入新的Goroutine中运行,那么主Goroutine会一直等待通道有足够的空间来接收数据,而填充操作又无法进行,从而导致死锁的产生。因此,为了避免死锁,我们需要在填充通道的操作中使用Goroutine来进行并发执行,以确保填充操作和接收操作可以同时进行。
我知道 sync
包及其 waitgroup
选项,我不想将其用于此测试。我正在测试一种信号量。
所以我有:
package main import ( "fmt" "os" "time" ) func main() { fmt.print("wassap") jobs := make(chan int) processstarted := make(chan struct{}, 1) processcompleted := make(chan struct{}, 1) createjobs(jobs) go func() { worker(jobs, processstarted, processcompleted) }() go func() { sync(processstarted, processcompleted) }() time.sleep(3600 * time.second) fmt.print("\nend of main...") interrupt := make(chan os.signal) <-interrupt } func createjobs(jobs chan<- int) { defer close(jobs) for i := 1; i < 20; i++ { jobs <- i } } func worker(jobs <-chan int, processstarted <-chan struct{}, processcompleted <-chan struct{}) { for { select { case i := <-jobs: fmt.printf("\nfetching job #%d from channel", i) time.sleep(2 * time.second) case <-processstarted: fmt.print("\nprocess started. waiting for it to be completed") <-processcompleted fmt.print("\nprocess completed") } } } func sync(processstarted chan<- struct{}, processcompleted chan<- struct{}) { // acquire semaphore. send signal to channel to indicate that it is busy processstarted <- struct{}{} for i := 1; i < 5; i++ { fmt.printf("\nprocessing %d", i) time.sleep(5 * time.second) } // release semaphore processcompleted <- struct{}{} }
我想要测试的非常简单:我有一个 createjobs
函数,其唯一目的是将元素添加到通道,在本例中是一个 int 通道。然后我有一个 worker
将从该通道中提取对象并在提取下一个元素之前休眠 2 秒。
现在,还有同步功能。该函数的唯一目的是模拟 worker
运行时启动的进程。如果此进程处于活动状态,则在 sync
结束时应停止处理 jobs
元素,这就是为什么我有两个通道,一个表示进程已启动,另一个表示进程结束。
运行我的代码时出现以下错误:
fatal error: all goroutines are asleep - deadlock!
如果我修改 createjobs
的调用方式,将其包装在如下所示的 goroutine 中:
go func() { createJobs(jobs) }()
然后我的代码运行正确。
我只是想了解为什么会发生这种情况。我的意思是: main
例程正在执行,然后它调用 main
例程正在执行,然后它调用 createjobs
(无换行),因此 main
例程应该被阻止,直到此调用结束。一旦 createjobs
结束,就说明通道中有元素了。 main
继续执行并启动其他 goroutine worker
和 sync
来完成它们的工作。在 main
(无换行),因此 main
例程应该被阻止,直到此调用结束。一旦
main
继续执行并启动其他 goroutine worker
和 sync
来完成它们的工作。在 main
结束之前,我只是添加一个睡眠程序,以便为之前创建的 goroutine 提供完成时间。
createjobs
发生在 goroutine 之外时会发生什么。
您将 jobs
声明为无缓冲通道,然后尝试将 20 个值同步推入其中。当您调用 createjobs(jobs)
我不是在询问这个问题的其他解决方案,我只是想知道当
jobs
声明为无缓冲通道,然后尝试将 20 个值同步推入其中。当您调用 时,这将阻止您的主函数。 将第 13 行更改为:
jobs := make(chan int, 20)
...将解决僵局。
编辑 - 评论中要求的澄清:createjobs(jobs)
无缓冲通道的一个很好的类比是管道,在本例中,过程如下所示:
+------------------+ +------------+ +-------------+ | PRODUCER | | PIPE | | CONSUMER | | +---->| +----->| | | createJobs(jobs) | | unbuffered | | worker(...) | | | | channel | | | +------------------+ +------------+ +-------------+发生死锁是因为
被同步调用,并且还没有消费者在运行。
main()
以上是当填充通道的函数调用未嵌入 Goroutine 中时,为什么会出现死锁?的详细内容。更多信息请关注PHP中文网其他相关文章!