golang chan(管道)

一、channel的理解可参考:[系列] Go - chan 通道 - 新亮笔记 - 博客园 (cnblogs.com)

主要点:

1、管道类似队列:队满时,入队会导致阻塞,队空时出队也会阻塞;

不带缓冲的通道,进和出都会立刻阻塞。不带缓冲的管道类似ch:=make(chan data_type,N),其中不带缓冲区是指大小参数N=0,或省略,则为非缓冲管道,即管道容量为N=0。

2、go 关键字后面加一个函数,就可以创建一个线程(goroutine),函数可以为已经写好的函数,也可以是匿名函数。

 

二、管道和select配合:

golang的select类似c语言、java中的switch语句,但有明显的区别:

switch语句会【逐个】执行各个case分支,然后执行default分支,除非某个case包含break语句则退出switch;

而select会【随机】地执行下面的各个非阻塞的case 语句,且每个case 语句必须是一个读或写channel的操作;当某个case 阻塞时会走到下一个case,若该case不阻塞则执行该case后退出select,若所有的case都阻塞才会执行default 分支。

package main

import "fmt"

func main() {
	// test_select()
	for i := 1; i <= 10; i++ {
		fmt.Println("Iter No.", i)
                //test_select()
		test_select2()

	}
}

func test_select() {
	var c1, c2, c3 chan int
	var i1, i2 int = 10, 20
	c3 = make(chan int, 6)
	c3 <- 50
	select {
	case i1 = <-c1:
		fmt.Println("received ", i1, " from c1\n")
	case c2 <- i2:
		fmt.Println("sent ", i2, " to c2\n")
		break
	case i3, ok := (<-c3): // same as: i3, ok := <-c3
		if ok {
			fmt.Println("received", i3, "from c3\n")
		} else {
			fmt.Println("c3 is closed\n")
		}
	default:
		fmt.Printf("no communication\n")
	}
}

func test_select2() {
	var c1, c2, c3 chan int
	var i1, i2 int = 10, 20
	c2 = make(chan int, 5)
	c3 = make(chan int, 3)
	c3 <- 50
	select {
	case i1 = <-c1:
		fmt.Println("received ", i1, " from c1")
	case c2 <- i2:
		fmt.Println("sent ", i2, " to c2")
		// break
	case c3 <- 5: // same as: i3, ok := <-c3
		// if ok {
		// 	fmt.Println("received", i3, "from c3\n")
		// } else {
		// 	fmt.Println("c3 is closed\n")
		// }
		fmt.Println("sent ", 5, " to c3")
	default:
		fmt.Printf("no communication\n")
	}
}

上述代码执行10次test_select()函数都是走到第3个case,若执行10次 test_select2(),则输出的结果会随机顺序执行第2、第3个case,因为它俩都不阻塞。

posted @ 2022-05-12 17:29  morein2008  阅读(131)  评论(0编辑  收藏  举报