go里的select特点|Go主题月

简介: 在go中有一个类似switch的关键字,那就是select。select的每个case接收的是I/O通讯操作,不能有其他表达式。select要配合channel使用。

网络异常,图片无法展示
|

简介


go中有一个类似switch的关键字,那就是select

select的每个case接收的是I/O通讯操作,不能有其他表达式。select要配合channel使用。

select的语法结构是这样的:

select {
    case 表达式:
      执行语句
    case 表达式 :
        执行语句
    default : 
        执行语句
}

上面的表达是可以是chan的写入(chan<-)或者是读取(<-chan)。

其中case的数量没有限制,每个case会随机执行。default是可选的,可以不用这个字段。但是当没有default时,select在没有接收到channel通道数据时就会被阻塞,所以为了程序的健壮性,建议还是带上default字段(default代码快可以为空)。

随机读取

我们可以用select来随机使用case来读取一个channel。代码可以这样写:

package main
import (
  "fmt"
  "time"
)
func main() {
  // 定义一个100容量的channel
  ch:=make(chan string,100)
  go func() {
    for  {
            // 向channel写入数据
      ch <- "hello go!"
      time.Sleep(1*time.Second)
    }
  }()
  for  {
    select {
            // 读取数据
            case i:= <- ch:
                fmt.Printf("第1个case:%s\n",i)
            case j:= <- ch:
                fmt.Printf("第2个case:%s\n",j)
            default:
    }
  }
}

上面这段代码中,我没每过一秒向ch里写入hello go!这个字符串数据。然后select语句中,两个case会随机进被执行,同时channel里的数据会被读取然后复制到对应变量上。当channel里的没有数据被读取时,default就会会被执行(虽然它里面没有执行代码块)。上面程序输出:

第1个case:hello go!
第2个case:hello go!
第1个case:hello go!
第2个case:hello go!
第2个case:hello go!
......

随机写入

select除了可以读取channel里的数据外,还可以向channel里写入数据。代码可以这样写:

package main
import (
  "fmt"
  "time"
)
func main() {
  ch:=make(chan string,100)
  go func() {
    for  {
            // 读取数据
      s:=<-ch
      fmt.Printf("接收数据:%s\n",s)
    }
  }()
  for  {
        // 随机写入
    select {
            case ch <- "第1个case写入":
            case ch <- "第2个case写入":
    }
    time.Sleep(1*time.Second)
  }
}

上面代码中,我们每过1秒中随机向ch通道里写入数据。由于select对于写操作总是会被执行,所以就不用default了。上面的代码会输出:

接收数据:第1个case写入
接收数据:第2个case写入
接收数据:第1个case写入
接收数据:第2个case写入
接收数据:第2个case写入
......

混合读写

当然我们可以在select里同时向通道读数据和写数据,不过要注意的是,当select里有多个case可以被执行时,select就会随机执行一个。也就是说每次只有一个case会被执行。为了便于理解,我们代码可以这样写:

package main
import (
  "fmt"
  "time"
)
func main() {
  // 创建两个通道
  ch:=make(chan string,100)
  ch2:=make(chan string,100)
    // 接收ch通道数据的协程
  go func() {
    for  {
      s:=<-ch
      fmt.Printf("接收数据:%s\n",s)
    }
  }()
  // 向ch2通道写入数据的协程
  go func() {
    for  {
      ch2 <- "新的通道"
      time.Sleep(1*time.Second)
    }
  }()
  // 计数
  num:=0
  for  {
    select {
    case ch <- "第1个case写入":
    case ch <- "第2个case写入":
    case s:= <- ch2:
      num++
      fmt.Printf("第3个case:%s,第%d次\n",s,num)
    }
    time.Sleep(1*time.Second)
  }
}

上面代码中,我们用前两个case来向ch通道里写入数据,第三个case来向ch2通道里读取数据。同时由于写操作总是会被执行,所以select不会被阻塞,也就不需要default了。我们加了一个num变量,以便理解select每次只执行一个case的效果。该程序最终会输出:

接收数据:第1个case写入
接收数据:第1个case写入
第3个case:新的通道,第1次
接收数据:第1个case写入
接收数据:第2个case写入
第3个case:新的通道,第2次
接收数据:第2个case写入
......

总结


通过上面的几个例子我们可以得出select的几个特点:

  • case里的表达式是向channel写数据时,这个case总是会被执行
  • 当有多个case可以被执行时,会随机执行其中一条
  • 每次只能有一个case被执行
  • 当没有case可执行时,default会被执行
  • 当没有case可执行时,同时也没有default时,select会被阻塞。
目录
相关文章
|
供应链 Go
掌握Go语言:利用Go语言的单向通道和select语句,提升库存管理效率(21)
掌握Go语言:利用Go语言的单向通道和select语句,提升库存管理效率(21)
135 0
|
5月前
|
人工智能 监控 Kubernetes
Go语言在select语句中实现优先级
Go语言中的`select`语句用于监控多个Channel的发送或接收操作,选择就绪的分支执行。它支持多种使用场景,如空`select`永久阻塞、单`case`阻塞读写、多`case`随机选择、配合`default`实现非阻塞操作等。通过嵌套`select`还可实现执行优先级,适用于如Kubernetes中任务调度等实际场景。
|
程序员 Go
Golang深入浅出之-Select语句在Go并发编程中的应用
【4月更文挑战第23天】Go语言中的`select`语句是并发编程的关键,用于协调多个通道的读写。它会阻塞直到某个通道操作可行,执行对应的代码块。常见问题包括忘记初始化通道、死锁和忽视`default`分支。要解决这些问题,需确保通道初始化、避免死锁并添加`default`分支以处理无数据可用的情况。理解并妥善处理这些问题能帮助编写更高效、健壮的并发程序。结合使用`context.Context`和定时器等工具,可提升`select`的灵活性和可控性。
243 2
|
3月前
|
Go 开发者
Go语言实战案例:使用select监听多个channel
本文为《Go语言100个实战案例 · 网络与并发篇》第5篇,详解Go并发核心工具`select`的使用。通过实际案例讲解如何监听多个Channel、实现多任务处理、超时控制和非阻塞通信,帮助开发者掌握Go并发编程中的多路异步事件处理技巧。
|
5月前
|
Go
理解 Go 语言中的 select 用法
本文深入解析了Go语言中`select`的用法,它类似于`switch case`,但仅用于通道(channel)的操作。文章通过多个示例说明了`select`的基本用法、避免死锁的方法、随机性特点以及如何实现超时机制。同时总结了`select`与`switch`的区别:`select`专用于通道操作,case执行是随机的,需注意死锁问题,且不支持`fallthrough`和函数表达式。
221 1
理解 Go 语言中的 select 用法
|
5月前
|
监控 Go 开发者
深入解析 go 语言中的 select 语句
在 Go 语言中,`select` 是专为并发编程设计的控制结构,用于在多个 channel 操作间进行非阻塞选择。它类似于 `switch`,但所有 case 分支必须是 channel 的 I/O 操作。本文通过通俗易懂的语言和丰富代码示例,详细讲解 `select` 的各种用法,包括基本语法、空 `select`、多分支选择、`default` 分支、特点总结及最佳实践,适合初学者和有经验的开发者学习参考。掌握 `select`,能有效提升 Go 并发编程的灵活性与效率。
189 6
|
5月前
|
Go 调度 开发者
Go 并发编程基础:select 多路复用
Go 语言中的 `select` 是一种强大的并发控制结构,用于同时监听多个通道操作。它支持随机选择就绪的通道、阻塞等待以及通过 `default` 实现非阻塞通信。结合 `time.After()`,可轻松实现超时机制,适用于网络请求、任务调度等场景。本文详细介绍了 `select` 的基本用法、特性及实战技巧,如合并多通道输入、处理通道关闭等,帮助开发者高效管理协程与通道交互,避免常见陷阱。
|
Go
go select 使用总结
go select 使用总结
136 1
|
Go
Go并发编程:玩转select语句
Go并发编程:玩转select语句
110 0
Go并发编程:玩转select语句