go-基础-channels-select-阻塞&非阻塞-range-timer-ticker

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() {
	// 传建一个管道,make(chan type, bufferNumber)
	message := make(chan string)
	go func() { message <- "ping" }() // 执行发送ping到管道上
	msg := <-message                  // 接收管理上的值并赋值给msg
	fmt.Println(msg)                  // 打印管道内容

	// 缓冲两个值
	msg2 := make(chan string, 2) // 设置两个对话的管道
	msg2 <- "channel"
	msg2 <- "buffered"  // 发送信息到管道
	fmt.Println(<-msg2) // 取出信息
	fmt.Println(<-msg2)

	// 阻塞
	done := make(chan bool, 1)
	go worker(done) // 阻塞等待,等到done有值
	<-done          // 等待并获取管道信息。所以这时候会回到go worker函数里面执行代码块,并发送done的值。这里如果没有要使用到done,上面的worker函数会提前结束执行

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

	// 获取异步信息 select 等待多个通道操作
	c1 := make(chan string)
	c2 := make(chan string)
	// 模拟并发,1s和2s异步操作,但同时执行
	go func() {
		time.Sleep(2 * time.Second)
		c1 <- "hello11" // 输入两次,则可读取两次
		c1 <- "hello22"
	}()
	go func() {
		time.Sleep(2 * time.Second) // 如果时间太短,会导致死锁,即同时读写。
		c2 <- "world"
	}()
	// 处理异步通道信息
	for i := 0; i < 2; i++ {
		select {
		case msg1 := <-c1:
			fmt.Println("received1", msg1)
		case msg2 := <-c2:
			fmt.Println("received2", msg2)
		}
	}
	fmt.Println("received1 out", <-c1) // <-里面如果为空只会报错

	// 超时,一个超时一个不超时的例子
	c3 := make(chan string, 1)
	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")
	}
	c4 := make(chan string, 1)
	go func() {
		time.Sleep(2 * time.Second)
		c4 <- "result 2"
	}()
	select {
	case res := <-c4:
		fmt.Println(res)
	case <-time.After(time.Second * 3):
		fmt.Println("timeout 2")
	}

	// 使用default实现非阻塞,不写默认处理会阻塞成为死锁。
	msg5 := make(chan string)
	signals := make(chan string)
	select {
	case msg := <-msg5:
		fmt.Println(msg)
	default:
		fmt.Println("no msg received")
	}
	msgStr1 := "hi"
	select {
	case msg5 <- msgStr1:
		fmt.Println("sent message", msg)
	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")
	}
	// 关闭管道:表示不会在其上接收以及发送更多值
	jobs := make(chan int, 5)
	done2 := make(chan bool)
	go func() {
		for { // 一直监听jobs的值
			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) // 关闭管道,发送完毕
	fmt.Println("sent all jobs")
	<-done2 // 要想输出值,就要去计算done的最终结果,故会执行并等待go函数的结果,以此为函数开关。

	// range 循环管道队列
	queue := make(chan string, 2)
	queue <- "one"
	queue <- "two"
	close(queue)
	for elem := range queue {
		fmt.Println("elem", elem)
	}

	// 一次定时器
	timer := time.NewTimer(2 * time.Second)
	<-timer.C
	fmt.Println("Time. 1 fired")
	// 除非为了可能在定时器发生前删除定时器,否则一般使用time.Sleep()即可。
	// 1s后执行定时器,然而下面获取了定时器后直接取消了。
	timer2 := time.NewTimer(time.Second)
	go func() {
		<-timer2.C
		fmt.Println("timer2 2 fired")
	}()
	stop2 := timer2.Stop()
	if stop2 {
		fmt.Println("t2 stop", stop2)
	}
	time.Sleep(2 * time.Second)

	// 永久定时器
	// go的并发处理就像是在钓鱼,不收鱼竿则一直在垂钓。
	ticker := time.NewTicker(500 * time.Microsecond)
	done4 := make(chan bool)
	go func() {
		for { // 内部循环,终止循环的钥匙放在另一个管理里面。
			select {
			case <-done4:
				return
			case t := <-ticker.C:
				fmt.Println("tick at", t)
			}
		}
	}()

	time.Sleep(1600 * time.Millisecond)
	// ticker.Stop()
	done4 <- true // 类似于 resolve(true), 来当做是一个停止管理去操作
	fmt.Println("ticker stopped")

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值