go中channel和goroutine以及select的配合使用

channel的创建和关闭:

 

ch:=make(chan int) ,初始化一个int类型的channel

使用Go内置函数close来关闭一个channel, close(ch)

 

注意:

1.向一个已经关闭的channel发送消息会程序会panic

2.关闭一个未初始化的channel会panic

3.可以从一个已经关闭的channel中读取消息,能够读取channel中未被读取的消息,如果所有消息均被读出,则会读到类型的零值。从一个已经关闭的channel中读取消息永远不会阻塞,ok,idiom:=<-ch, 如果ok为真则未关闭,false则已经关闭。

4.channel关闭时候,所有的goroutine都会受到消息

 

无缓存的channel

 

从无缓存的channel中读取消息会阻塞,直到有goroutine向此channel中发送消息,向无缓存的channel中发消息也会阻塞,直到有goroutine向该channel中读取消息。

 

实例代码:

//读数据
var ch chan int
ch = make(chan int)
//close(ch)

go func() {
	fmt.Println("A")
	_ = <-ch //阻塞在这里,不会打印B
	fmt.Println("B")
}()

time.Sleep(time.Second * time.Duration(5))



//存数据
var ch chan int
ch = make(chan int)
//close(ch)

go func() {
	fmt.Println("A")
	ch <- 8 //阻塞在这里,不会打印B
	fmt.Println("B")
}()

有缓存的channel

 

有缓存的 channel 类似一个阻塞队列(采用环形数组实现)。当缓存未满时,向 channel 中发送消息时不会阻塞,当缓存满时,发送操作将被阻塞,直到有其他 goroutine 从中读取消息;相应的,当 channel 中消息不为空时,读取消息不会出现阻塞,当 channel 为空时,读取操作会造成阻塞,直到有 goroutine 向 channel 中写入消息

 

make函数的第二个参数来指定缓存的容量

 

实例代码:

var ch chan int
ch = make(chan int,1)
//close(ch)

go func() {
	fmt.Println("A")
	_ = <-ch //阻塞,尽管有缓存,但是channel是空的没有放入消息
	fmt.Println(”B”)
     _ = <-ch //阻塞,不会打印C
	fmt.Println("C")

}()

time.Sleep(time.Second * time.Duration(5))

channel的遍历

 

注意:channel可以用range取值,并且一直会从channel中取值,直到有goroutine把channel关闭循环才会结束。

 

示例代码:

var ch chan int
ch = make(chan int, 0)

go func() {
	for v := range ch { //循环直到有goroutine close(ch)
		fmt.Println(v)
	}
}()
ch <- 1
ch <- 2
ch <- 3
time.Sleep(time.Second * 5) //睡眠5
ch <- 4
ch <- 5
close(ch)

输出:12345,其中45是在main函数睡眠5秒后输出,range一直在持续,直到close(ch)

 

也可以使用 :

for {

      c, ok := <-ch

      if !ok {

         break

      }

}

这种方式来遍历。

 

select和channel的配合使用

注意:

1.select可以同时监听多个channel的写入或读取

2.执行select若只有一个case不阻塞,则执行这个case块

3.若多个case不阻塞,则随机挑选一个执行

4.若所有case都阻塞则实行default块,若未定义default则select语句阻塞

直到有case被唤醒

5.使用break跳出select

示例代码:

ch1 := make(chan int)
ch2 := make(chan int)
ch3 := make(chan int)
ch4 := make(chan int)

select {
case <-ch1:
	fmt.Println("A")
case <-ch2:
	fmt.Println("B")
case <-ch3:
	fmt.Println("C")
case <-ch4:
	fmt.Println("D")
default:
	fmt.Println("E") //全部阻塞,执行default
}

fmt.Println("F")

示例代码2:

ch1 := make(chan int)
ch2 := make(chan int)
ch3 := make(chan int)
ch4 := make(chan int)

go func() {
	fmt.Println("1")
	ch1 <- 1
	fmt.Println("2")
	ch2 <- 2
	fmt.Println("3")
	ch3 <- 3

}()
time.Sleep(time.Second * 1)
select {
case <-ch1:
	fmt.Println("A")
case <-ch2:
	fmt.Println("B")
case <-ch3:
	fmt.Println("C")
case <-ch4:
	fmt.Println("D")
default:
	//fmt.Println("E") //全部阻塞,执行default
}

fmt.Println("F")

//输出: 1 
//     A
//     F
//     2

    首先执行goroutine 会打印1 此时给ch1赋值 会阻塞,1秒后当执行select 则case ch1通过打印A,此时 goroutine 被唤醒 同时main函数也会继续执行 则打印F、2,main函数退出 .

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值