Golang Select & 定时器

1. Select

select: 管理多个channel,监听channel上的数据流动。类似switch语法,但每个case语句必须是IO操作。多个case同时满足,任选一个执行。

  • 处理一个或多个channel的发送和接收
  • 同时有多个channel时,随机处理
  • 可用空select来阻塞main函数
  • 可设置超时

default语句:

  • 有default:select语句不会被阻塞,执行default后,程序的执行会从select语句中恢复,进入下一次轮询。比较消耗资源。
  • 没有default:select语句将被阻塞,直到至少有一个通信可以进行下去

1.1 管理多个通道

func main() {
	ch := make(chan int)
	done := make(chan bool)

	// 消费者
	go func() {
		for i := 0; i < 10; i++ {
			fmt.Printf("%d ", <-ch)
		}
		fmt.Println()

		done <- true
	}()

	fib(ch, quit)
}

func fib(ch chan<- int, quit <-chan bool) {
	x, y := 1, 1

	for {
		select {
		case ch <- x:
			x, y = y, x+y
		case <-done:
			fmt.Println("Done.")
			return // break只能跳出select,无法跳出for循环
		}
	}
}

1.2 作为发送者

func main() {
	c := make(chan int)

	go func() {
		for v := range c {
			fmt.Println(v)
		}
	}()

	for i := 0; i < 100; i++ {
		select {
		case c <- 0:
		case c <- 1:
		}
	}
}

1.3 超时处理

case <-time.After(5 * time.Second): 其他channel阻塞时间超过5s时执行

func main() {
	ch := make(chan int)
	done := make(chan bool)

	go func() {
		for {
			select {
			case x := <-ch:
				fmt.Printf("%d ", x)
			case <-time.After(5 * time.Second):
				fmt.Println("\nTimeout")
				done <- true
				return
			}
		}
	}()

	for i := 0; i < 10; i++ {
		ch <- i
		time.Sleep(time.Second)
	}

	<-done
}

1.4 避免造成死锁

select 在执行过程中,必须命中其中的某一分支, 否则deadlock

func main() {
	c1 := make(chan string, 1)
	c2 := make(chan string, 1)

	c1 <- "ok"
	c2 <- "good"

	select {
	case msg := <-c1:
		fmt.Printf("c1 receive %s\n", msg)
	case msg := <-c2:
		fmt.Printf("c2 receive %s\n", msg)
	default:
		fmt.Println("no data")
	}
}

2. 定时器

2.1 一次性定时任务

time.NewTimer(d Duration) *Timer

  • <-timer.C: 阻塞等待,返回定时器时间
  • timer.Stop():
  • timer.Reset(d Duration):
func main() {
	timer := time.NewTimer(2 * time.Second)

	go func() {
		<-timer.C
		fmt.Println("Goroutine is done.")
	}()

	timer.Stop()

	// 重置定时器,上面的 goroutine 将继续执行
	timer.Reset(5 * time.Second)

	select {
	case <-time.After(10 * time.Second):
	}
}

2.2 周期性定时任务

time.NewTicker(d Duration) *Ticker

  • <-ticker.C: 阻塞等待,返回定时器时间
  • ticker.Stop():
func main() {
	ticker := time.NewTicker(2 * time.Second)

	count := 0
	for {
		<-ticker.C

		count++
		fmt.Printf("%d ", count)

		if count == 10 {
			ticker.Stop()
			break
		}
	}
	fmt.Println()
}

2.3 延迟操作总结

time.Sleep(time.Second * 2)

<- time.After(time.Second * 2)

timer := time.NewTimer(time.Second * 2)
<-timer.C
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值