go-chan例子及理解

一、基本输入输出

  1. 普通阻塞
  2. 容量管道
  3. 阻塞异步操作工作任务,基础控制阻塞模式:通过开关来引起阻塞
  4. 发送和接收,模拟消息

二、select的使用

  1. 获取异步信息,异步发送, for-select-case 挂起等待读取数据
  2. 超时,一个超时一个不超时的例子,使用time.After设置超时执行
  3. select-default跳出阻塞

三、close的使用

  1. close关闭写入,允许读取。close+more && for-if && 开关,读取所有chan值。

四、定时器

  1. 定时器,控制chan阻止阻塞发生,这样就不会走gorun
  2. 延时器
package main

import (
	"fmt"
	"time"
)

func worker(done chan bool) {
	fmt.Println("working...")
	time.Sleep(time.Second)
	fmt.Println("done")
	done <- true // 写入信息到管道内
}

func ping(pings chan<- string, msg string) {
	// 这里pings是出入类型
	pings <- msg
}
func pong(pings <-chan string, pongs chan<- string) {
	msg := <-pings // 这里pings是输出类型
	pongs <- msg
}
func main() {
	// 1. 普通阻塞
	message := make(chan string)      // 传建一个频道管道,内容类型是字符串
	go func() { message <- "ping" }() // 执行发送ping到管道上
	msg := <-message                  // 接收管理上的值并赋值给msg,没有容量导致阻塞,去执行gorun找到输入。
	fmt.Println(msg)                  // 打印管道内容

	// 2. 容量管道
	// 缓冲两个值
	msg2 := make(chan string, 2) // 设置两个对话的管道,表示有两个缓存区,不会阻塞。如果没有第二参数则会导致阻塞。
	msg2 <- "buffered"
	msg2 <- "channel"
	fmt.Println(<-msg2) // 取出信息
	fmt.Println(<-msg2)

	// 3. 阻塞异步操作工作任务,基础控制阻塞模式:通过开关来引起阻塞
	// 通知工作完成
	done := make(chan bool, 1)
	go worker(done)
	<-done // 获取管道信息

	// 4. 发送和接收,模拟
	pings := make(chan string, 1)
	pongs := make(chan string, 1)
	ping(pings, "hello chan") // 输入pings接收方管道
	pong(pings, pongs)        // 从接收方管道读取输出到结果方管道
	fmt.Println(<-pongs)      // 从结果管理取出数据

	// 5. 获取异步信息,异步发送,等待读取数据
	c1 := make(chan string)
	c2 := make(chan string)
	go func() {
		time.Sleep(2 * time.Second) // 模拟异步延迟
		c1 <- "hello11" // 输入两次,则可读取两次
		c1 <- "hello22"
	}()
	go func() {
		time.Sleep(1 * time.Second) 
		c2 <- "world"
	}()
	
	for i := 0; i < 2; i++ { // 获取异步数据,取全部数据
		select { // 待机输出管道信息
		case msg1 := <-c1: // 没有容量导致发生阻塞,进入上面的gorun
			fmt.Println("received1", msg1) // hello11
		case msg2 := <-c2: // 同上
			fmt.Println("received2", msg2) // world
		}
	}
	fmt.Println("received1 out", <-c1) // hello22,如果循环三条数据出去,则这里再取数据会报错 deadlock。

	// 6. 超时,一个超时一个不超时的例子,使用time.After设置超时执行
	c3 := make(chan string)
	go func() {
		time.Sleep(2 * time.Second)
		c3 <- "result 1"
	}()
	select {
	case res := <-c3:
		fmt.Println(res)
	case <-time.After(1 * time.Second): // 超时1s
		fmt.Println("timeout 1")
	}

	// 7. select-default跳出阻塞,不写默认处理会阻塞成为死锁。
	msg5 := make(chan string, 1)
	signals := make(chan string, 1)
	select {
	case msg := <-msg5: // 发生阻塞,走default
		fmt.Println(msg)
	default:
		fmt.Println("no msg received")
	}
	msgStr1 := "hi"
	select {
	case msg5 <- msgStr1: // 写入
		fmt.Println("sent message", msgStr1)
	default:
		fmt.Println("no meg sent")
	}
	select {
	case msg := <-msg5: // 读取
		fmt.Println("receive msg", msg)
	case sig := <-signals: // 发生阻塞
		fmt.Println("receive signal", sig)
	default:
		fmt.Println("no activity")
	}
	// 8. close关闭写入,允许读取。close+more && for-if && 开关,读取所有chan值。
	jobs := make(chan int, 5)
	done2 := make(chan bool) // 开关,开启gorun程序输出
	go func() {
		for { // 一直监听jobs的值,通过more判断是否还有更多,结束循环。
			j, more := <-jobs // 返回值和是否还有下一个(布尔值),迭代器
			if more {
				fmt.Println("received job", j)
			} else {
				fmt.Println("receive all jobs")
				done2 <- true // 写入数据并退出函数,关闭监听。
				return
			}
		}
	}()
	for i := 0; i < 3; i++ {
		jobs <- i // 发送值给jobs
		fmt.Println("sent job", i)
	}
	close(jobs) // 关闭管道,发送完毕,设置第四个容量,让上面的jobs循环三次后第四次输出false来让程序进入else.如果没有close会导致进不到else从而jobs一直在读取但没有值最后出现死锁。
	fmt.Println("sent all jobs")
	<-done2 // 这里发生阻塞,导致进入gorun,开启上面的for循环,读取done管道数据。直到管道没有容量,结束循环取得done的值。

	// 9. 定时器,控制chan阻止阻塞发生,这样就不会走gorun
	timer := time.NewTimer(2 * time.Second)
	<-timer.C
	fmt.Println("Time. 1 fired")

	timer2 := time.NewTimer(time.Second)
	go func() {
		<-timer2.C
		fmt.Println("timer2 2 fired")
	}()
	stop2 := timer2.Stop() // 控制定时器停止,这样gorun里面不会输出,不然下面的sleep会导致阻塞进入gorun。这里是将内部的定时器设置为nil来取消chan的阻塞。
	if stop2 {
		fmt.Println("t2 stop", stop2)
	}
	time.Sleep(2 * time.Second)

	// 延时器
	ticker := time.NewTicker(500 * time.Microsecond) // 一个延迟执行的chan,输出时间
	done4 := make(chan bool)
	go func() {
		for { // 内部循环,终止循环的钥匙放在另一个管理里面。
			select {
			case <-done4:
				return
			case t := <-ticker.C:
				fmt.Println("tick at", t)
			}
		}
	}()

	time.Sleep(50 * time.Millisecond) // 调起程序,执行 goruntines,根据调起程序的时间执行多次ticker。
	ticker.Stop() // 如果不stop则会执行多次ticker。
	done4 <- true // 类似于 resolve(true), 来当做是一个停止管理去操作
	fmt.Println("ticker stopped")
	
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值