当前位置: 首页 > news >正文

【Go语言分析 select case 】

select

    • 基础用法
    • 使用场景
      • 超时管理
      • 无阻塞获取值
      • 类事件驱动循环
      • 带优先级的任务队列

select是Go语言在语言层面上提供的一个多路复用机制 它可以检测多个channel是否就绪

基础用法

Go语言select有如下的几个特点

  • select中各个case执行顺序是随机的
  • 如果某个case中的channel已经ready 则执行相应的语句并退出select流程
  • 如果所有的case的channel都没有ready 则有default会走default然后退出select 没有default select将阻塞直至channel ready
  • case后面不一定是读channel 也可以写channel 只要是对channel的操作就可以
  • 空的select语句将被阻塞 直至panic 但是通常情况下 我们不会使用空的select语句 因为这会导致一个协程一直阻塞

下面我们使用几段代码来一一讲解select的特点

  • select中各个case执行顺序是随机的
	select {
	case <-chan1: // 如果chan1成功读取到数据 则执行该操作
	// ...
	case chan2 <- 1: // 如果chan2成被写入数据 则执行该操作
	// ...
	}

如果说此时 chan1成功读取到了数据的同时chan2成功被写入了数据 那么就会随机选择一个case执行


  • select没有case 永久阻塞
	select {
	}

如果说我们使用一个协程执行了上面这段代码 那么在该协程会永久阻塞

注意 虽然说Go语言有死锁机制 会自动检测是否所有协程是否被阻塞 但是这是建立在所有协程都进入死锁的情况 如果说只是这一个协程阻塞 其他协程没有被阻塞那么此时不会发生panic错误的


  • 如果所有的case的channel都没有ready 则有default会走default然后退出select 没有default select将阻塞直至channel ready
select {
case <-chan1:
    // 如果chan1已经准备好接收数据,则执行此case。
    // ...
case chan2 <- 1:
    // 如果chan2已经准备好发送数据,则执行此case。
    // ...
default:
    // 如果上述channel都未准备好,立即执行default case。
    // ...
}

如果说此时没有channel准备好 则立刻执行default语句

使用场景

超时管理

// 设置一个1秒的超时时间
timeout := time.After(1 * time.Second)
// 假设这是一个异步操作的结果通道
operationCh := make(chan string)

select {
case result := <-operationCh:
    // 处理异步操作的结果
    fmt.Println("操作成功:", result)
case <-timeout:
    // 如果1秒钟内操作没有完成,会执行这个case
    fmt.Println("操作超时")
}

如果说我们不想无限制的执行该select操作 那么我们可以设置一个类似超时器 设定一个超时时间 如果说在该时间内没有读取到数据 那么我们就终止该select

无阻塞获取值

// 创建一个通道
messageChan := make(chan string, 1) // 缓冲通道,避免死锁

// 非阻塞地从通道接收数据
select {
case msg := <-messageChan:
    fmt.Println("收到消息:", msg)
default:
    fmt.Println("没有新消息")
}

// 向通道发送数据
messageChan <- "Hello, World!"

// 再次非阻塞地从通道接收数据
select {
case msg := <-messageChan:
    fmt.Println("收到消息:", msg)
default:
    fmt.Println("没有新消息")
}

上面的代码就是一段典型的无阻塞获取值的代码

在第一个select中 我们没有读取到数据 所以说立即打印没有新消息

在第二个select中 我们读取到了新的数据 所以说会立即打印 hello world

类事件驱动循环

type node struct {
    heartbeat chan struct{}
    conn struct {
        Close func()
    }
}

func (n *node) heartbeatDetect() {
    // 创建一个重置的定时器
    timeoutDuration := 3 * time.Second
    heartbeatTimer := time.NewTimer(timeoutDuration)

    for {
        select {
        case <-n.heartbeat:
            // 收到心跳信号,重置定时器
            if !heartbeatTimer.Stop() {
                <-heartbeatTimer.C
            }
            heartbeatTimer.Reset(timeoutDuration)
        case <-heartbeatTimer.C:
            // 心跳超时,关闭连接
            n.conn.Close()
            return
        }
    }
}

在这个代码中 heartbeatDetect方法属于node结构体 node具有一个heartbeat通道 用于接收心跳信号 以及一个conn字段模拟网络连接 其中包含一个Close方法来关闭连接

函数首先创建了一个心跳定时器heartbeatTimer 用于跟踪心跳的超时

在for循环中 select语句监听心跳通道和定时器的通道

当心跳信号到达(通过n.heartbeat通道接收到) 该函数会尝试停止定时器 并且如果通道中有未处理的超时事件 则将其清除 以避免收到虚假的超时 然后它会重置定时器 开始新一轮的心跳等待

如果在规定时间内没有收到心跳(定时器的通道heartbeatTimer.C发出信号) 则会执行关闭连接的逻辑 并退出函数

带优先级的任务队列

highPriority := make(chan string, 5) // 高优先级任务队列
lowPriority := make(chan string, 5)  // 低优先级任务队列

// 添加任务到不同优先级的队列
go func() {
    highPriority <- "紧急任务"
    lowPriority <- "一般任务"
    highPriority <- "非常紧急任务"
}()

// 处理任务
for {
    select {
    case task := <-highPriority:
        // 首选处理高优先级任务
        fmt.Println("处理高优先级任务:", task)
        continue  // 继续下一个循环迭代,确保再次检查高优先级队列
    default:
    }

    select {
    case task := <-highPriority:
        // 再次检查高优先级任务队列,确保没有遗漏
        fmt.Println("处理高优先级任务:", task)
    case task := <-lowPriority:
        // 如果没有高优先级任务,则处理低优先级任务
        fmt.Println("处理低优先级任务:", task)
    }
}

我们可以使用多次select的方式来实现一个伪优先级任务队列

相关文章:

  • 力扣题:字符的统计-12.4
  • JVM 运行时参数
  • 高级系统架构设计师之路
  • 物理结构设计要点
  • 约瑟夫生死游戏
  • office办公技能|ppt插件使用
  • 前端笔记(四)Flex 布局
  • java WebSocket带参数处理使用
  • 佳明(Garmin) fēnix 7X 增加小睡检测功能
  • 在windows下编译libiconv库
  • 基于JavaWeb+SSM+Vue微信小程序的科创微应用平台系统的设计和实现
  • HarmonyOS--ArkTS(1)--基本语法(1)
  • 【Python网络爬虫入门教程1】成为“Spider Man”的第一课:HTML、Request库、Beautiful Soup库
  • 使用Java实现基数排序算法
  • Windows 和 MacOS 上安装配置ADB(安卓调试桥)
  • 【人生苦短,我学 Python】(5)集合数据类型(set、frozenset)
  • 【小沐学Python】Python实现TTS文本转语音(speech、pyttsx3、百度AI)
  • 理解基于 Hadoop 生态的大数据技术架构
  • c++学习之异常
  • 18.Java程序设计-基于Springboot的电影院售票系统的设计与实现
  • 首批证券公司科创债来了!拟发行规模超160亿元
  • 中消协点名新能源汽车行业:定金退款争议频发
  • 两部上戏学生作品亮相俄罗斯“国际大学生戏剧节”
  • 美政府被曝下令加强对格陵兰岛间谍活动,丹麦将召见美代办
  • 常州市委原常委、组织部部长陈翔调任江苏省民宗委副主任
  • 司法部:持续规范行政执法行为,加快制定行政执法监督条例