为什么这里发生了僵局

zer*_*ing 6 go

我试图了解golang频道的工作原理.我读了一本关于go语言的书,并找到了以下示例.

package main

import (
    "fmt"
)

// Send the sequence 2, 3, 4, ... to returned channel 
func generate() chan int {
    ch := make(chan int)
    go func() {
        for i := 2; i <= 100 ; i++ {
            ch <- i
        }
    }()
    return ch
}

// Filter out input values divisible by 'prime', send rest to returned channel
func filter(in chan int, prime int) chan int {
    out := make(chan int)
    go func() {
        for {
            if i := <-in; i%prime != 0 {
                out <- i
            }
        }
    }()
    return out
}

func sieve() chan int {
    out := make(chan int)
    go func() {
        ch := generate()
        for {
            prime := <-ch
            ch = filter(ch, prime)
            out <- prime
        }
    }()
    return out
}

func main() {
    primes := sieve()
    for {
        fmt.Println(<-primes)
    }
}
Run Code Online (Sandbox Code Playgroud)

当我运行这个程序时,我遇到了死锁,但是当我将生成函数更改为

// Send the sequence 2, 3, 4, ... to returned channel 
func generate() chan int {
    ch := make(chan int)
    go func() {
        for i := 2; ; i++ {
            ch <- i
        }
    }()
    return ch
}
Run Code Online (Sandbox Code Playgroud)

然后程序将运行无限循环,但不会死锁.当我在for循环中删除条件时,为什么会出现死锁?

Von*_*onC 9

阻塞原则是什么意思?

你可以看到它在博客中说明" 频道的性质转到 "

对于无缓冲的频道:

http://3.bp.blogspot.com/-vnJIWvlbP-E/UwDVICJKB9I/AAAAAAAANX0/T04V_58i8Vs/s1600/Screen+Shot+2014-02-16+at+10.10.54+AM.png

(来自博客文章" 走进频道的本质 " 插图,由William Kennedy撰写,2014年2月)

无缓冲通道没有容量,因此需要两个goroutine准备进行任何交换.
当goroutine尝试将资源写入无缓冲通道并且没有goroutine等待接收资源时,通道将锁定goroutine并使其等待.
当goroutine尝试从无缓冲的通道读取,并且没有goroutine等待发送资源时,通道将锁定goroutine并使其等待.

这就是你的读者在你的情况下发生的事情:

func main() {
    primes := sieve()
    for {
        fmt.Println(<-primes)
    }
}
Run Code Online (Sandbox Code Playgroud)

因为primes从未关闭,main仍然被阻止.
它(main)在第3步:

在步骤3中,右侧的goroutine将手放入通道或执行读取.
在交换完成之前,goroutine也被锁定在频道中.

发件人从不打电话close(primes).


Fre*_*Foo 5

让我们考虑一个更简单的例子:

func generate() chan int {
    ch := make(chan int)
    go func() {
        for i := 2; /*i < 100*/; i++ {
            ch <- i
        }
    }()
    return ch
}

func main() {
    for i := range generate() {
        fmt.Println(i)
    }
}
Run Code Online (Sandbox Code Playgroud)

在条件未i < 100注释的情况下,goroutine generate在发送98个数字后停止产生.但是,它不会关闭频道,因此main无法知道将不再发送任何数字,并且它只是在频道上保持阻塞.既然main现在是唯一仍然存在的goroutine(另一个已经返回),并且它正在阻塞,那么你就陷入了僵局.