📜  Golang 中的缓冲通道

📅  最后修改于: 2021-10-25 02:47:00             🧑  作者: Mango

通道可以定义为Goroutine通信的管道。类似于水在管道中从一端流向另一端,数据可以使用通道从一端发送并从另一端接收。默认情况下,通道是无缓冲的,这表明如果有相应的接收 (<- chan) 准备好接收发送的值,它们将只接受发送 (chan <-)。缓冲通道允许接受有限数量的值,而这些值没有相应的接收器。可以创建一个带有缓冲的通道。缓冲通道仅在缓冲区已满时才被阻塞。类似地,仅当缓冲区为空时才阻止从缓冲通道接收。

可以通过将额外的容量参数传递给指定缓冲区大小的make()函数来创建缓冲通道。

此处,上述语法中的容量应大于 0 才能使通道具有缓冲区。默认情况下,无缓冲通道的容量为 0,因此省略了容量参数。

示例 1:创建缓冲通道的代码。

Go
package main
  
import (
    "fmt"
)
  
func main() {
  
    // create a buffered channel 
    // with a capacity of 2.
    ch := make(chan string, 2)
    ch <- "geeksforgeeks"
    ch <- "geeksforgeeks world"
    fmt.Println(<-ch)
    fmt.Println(<-ch)
}


Go
package main
  
import (
    "fmt"
    "time"
)
  
func write(ch chan int) {
    for i := 0; i < 4; i++ {
        ch <- i
        fmt.Println("successfully wrote", i, "to ch")
    }
    close(ch)
}
func main() {
  
    // creates capacity of 2
    ch := make(chan int, 2)
    go write(ch)
    time.Sleep(2 * time.Second)
    for v := range ch {
        fmt.Println("read value", v, "from ch")
        time.Sleep(2 * time.Second)
  
    }
}


Go
package main
  
import (
    "fmt"
)
  
func main() {
    ch := make(chan string, 2)
    ch <- "geeksforgeeks"
    ch <- "hello"
    ch <- "geeks"
    fmt.Println(<-ch)
    fmt.Println(<-ch)
}


输出:

geeksforgeeks
geeksforgeeks world

在上面的代码中,可以在不被阻塞的情况下将 2 个字符串写入通道。它需要 2 个字符串到通道并且不会阻塞并打印结果。

示例 2:写入缓冲通道块的程序。

package main
  
import (
    "fmt"
    "time"
)
  
func write(ch chan int) {
    for i := 0; i < 4; i++ {
        ch <- i
        fmt.Println("successfully wrote", i, "to ch")
    }
    close(ch)
}
func main() {
  
    // creates capacity of 2
    ch := make(chan int, 2)
    go write(ch)
    time.Sleep(2 * time.Second)
    for v := range ch {
        fmt.Println("read value", v, "from ch")
        time.Sleep(2 * time.Second)
  
    }
}

输出:

successfully wrote 0 to ch
successfully wrote 1 to ch
read value 0 from ch
successfully wrote 2 to ch
read value 1 from ch
successfully wrote 3 to ch
read value 2 from ch
read value 3 from ch

在上面的代码中, write Goroutine 有一个 for 循环,它将 0 到 3 的数字写入 ch 通道。此缓冲通道的容量为 2,因此写入 Goroutine 将能够立即将值 0 和 1 写入 ch 通道,然后它会阻塞,直到从 ch 通道读取至少一个值,如下定义:-

successfully wrote 0 to ch
successfully wrote 1 to ch

之后,读取值然后再次休眠 2 秒,这个循环一直持续到 ch 关闭。所以程序将在 2 秒后打印以下几行,如:-

read value 0 from ch  
successfully wrote 2 to ch 

这将一直持续到所有值都写入通道并在写入Goroutine 中关闭。

缓冲 Golang 通道中的死锁

它被定义为程序在执行过程中由于运行时恐慌而导致致命错误的情况。

例子 :

package main
  
import (
    "fmt"
)
  
func main() {
    ch := make(chan string, 2)
    ch <- "geeksforgeeks"
    ch <- "hello"
    ch <- "geeks"
    fmt.Println(<-ch)
    fmt.Println(<-ch)
}

在这里,在上面的代码中,由于通道已超出其容量并且程序达到死锁情况,因此写入被阻止并打印以下消息:

fatal error: all goroutines are asleep - deadlock!



goroutine 1 [chan send]:

main.main()

    /tmp/sandbox048494311/prog.go:11 +0x8d