golang select

文章介绍了Go语言中的select关键字用于同时等待多个Channel的可读写状态,通过案例展示了其基本用法。在内部,select通过hselect、scase和sudog等结构体实现,并在runtime层由selectgo函数处理并发调度。优化策略包括轮询算法避免case饥饿和使用sudog缓存池减少内存开销。
摘要由CSDN通过智能技术生成

select 的基本用法:select 可以让 Goroutine 同时等待多个 Channel 的可读或可写状态,然后执行对应的 case 语句。

package main

import (
	"fmt"
	"time"
)

func main() {
	ch1 := make(chan int) // 创建一个整数类型的通道
	ch2 := make(chan int) // 创建另一个整数类型的通道

	go func() {
		time.Sleep(3 * time.Second) // 模拟耗时操作
		ch1 <- 100                  // 向ch1发送数据
	}()

	go func() {
		time.Sleep(5 * time.Second) // 模拟耗时操作
		ch2 <- 200                  // 向ch2发送数据
	}()

	select {
	case x := <-ch1: // 如果ch1有数据可接收,则执行这个分支
		fmt.Println("Received", x)
	case y := <-ch2: // 如果ch2有数据可接收,则执行这个分支
		fmt.Println("Received", y)
	default: // 如果没有任何case满足条件,则执行这个分支
		fmt.Println("No data received")
	}
}

在这个例子中,我们创建了两个整数类型的通道ch1和ch2,并分别在两个goroutine(轻量级线程)中向它们发送数据。然后我们使用select语句来监听这两个通道上是否有数据可接收。因为我们在发送数据之前都加了延时操作,所以当我们运行select语句时,没有任何case满足条件,所以会执行default分支打印"No data received"。

select 的数据结构:

select 的运行时结构包括 hselect 结构体、 scase 结构体和 sudog 结构体。hselect 结构体表示一个 select 操作,它包含了一个 scase 数组和一个 sudog 数组。scase 结构体表示一个 case 语句,它包含了一个 Channel 指针、一个元素指针、一个操作类型等字段。sudog 结构体表示一个等待在 Channel 上的 Goroutine,它包含了一个 Goroutine 指针、一个 scase 指针等字段。这些结构体之间通过链表或者数组来连接。

select 的实现原理:

select 的编译过程主要分为两步:第一步是生成汇编代码,这个过程会创建 hselect 和 scase 结构体,并将它们传递给 runtime.selectgo 函数;第二步是调用 runtime.selectgo 函数,这个函数会执行以下操作:首先检查是否有 Channel 已经就绪,如果有就随机选择一个执行对应的 case 语句;其次如果没有就绪的 Channel,就将当前 Goroutine 加入到每个 Channel 的等待队列中,并将当前 Goroutine 置为休眠状态;最后当有 Channel 就绪时,就唤醒对应的 Goroutine,并执行相应的 case 语句。

select 的优化策略:

Go 语言对 select 的一些优化技巧包括使用轮询算法来随机选择 case 语句、使用缓存池来复用 sudog 结构体等。轮询算法可以避免某些 case 语句被频繁选择而导致其他 case 语句被饿死;缓存池可以减少内存分配和垃圾回收的开销。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值