go语言中如何使用select的实现示例

目录
  • 1.基本语法
  • 2.select语句的实际应用

在golang语言中,select语句 就是用来监听和channel有关的IO操作,当IO操作发生时,触发相应的case动作。

有了 select语句,可以实现 main主线程 与 goroutine线程 之间的互动。

1.基本语法

select {
    case <-ch1 :     // 检测有没有数据可读
        // 一旦成功读取到数据,则进行该case处理语句
    case ch2 <- 1 :  // 检测有没有数据可写
        // 一旦成功向ch2写入数据,则进行该case处理语句
    default:
        // 如果以上都没有符合条件,那么进入default处理流程
}

注意事项

  • select语句 只能用于channel信道的IO操作,每个case都必须是一个信道。
  • 如果不设置 default条件,当没有IO操作发生时,select语句就会一直阻塞;
  • 如果有一个或多个IO操作发生时,Go运行时会随机选择一个case执行,但此时将无法保证执行顺序;
  • 对于case语句,如果存在信道值为nil的读写操作,则该分支将被忽略,可以理解为相当于从select语句中删除了这个case;
  • 对于空的 select语句,会引起死锁;
  • 对于在 for中的select语句,不能添加 default,否则会引起cpu占用过高的问题;

(1)多个IO操作发生时,case语句是随机执行的

func main()  {
    ch1 := make(chan int, 1)   // 创建 一个长度带缓冲的整型通道
    ch1 <- 1                   // 向通道中写入数据

    ch2 := make(chan int, 1)
    ch2 <- 2

    select {
        case <- ch1:
            fmt.Println("ch1 read")
        case <- ch2:
            fmt.Println("ch2 read")
    }
}

多次执行后,会随机打印 “ch1 read” 或 “ch2 read”

(2)空select语句

func main()  {
    select {

    }
}

执行后,引发死锁,打印如下:

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [select (no cases)]:
main.main()
        xxx/test.go:4 +0x27
exit status 2

(3)for中的select 引起CPU资源消耗过高

func main()  {
    quit := make(chan bool)
    go func() {
        for {
            select {
            case <-quit:
                fmt.Println("quit")
                // 使用 return 就会退出整个goroutine线程;如果使用 break,程序仍然在for循环中执行
                return
            default:
                fmt.Println("default")
            }
        }
    }()

    time.Sleep(3 * time.Second)
    quit <- true          // 主线程在3秒后,向quit信道写入数据
    
    time.Sleep(2 * time.Second)
    fmt.Println("main")
}

在for{}的select语句中使用了 default后,线程就会无限执行default条件,直到quit信道中读到数据,否则会一直在一个死循环中运行,从而导致占满整个CPU资源。

在 for{}的select语句中,不建议使用 default条件。

2.select语句的实际应用

(1)实现 main主线程与 goroutine线程 之间的交互、通信

// 通过控制台输入 "bye", 来控制main函数结束运行
func main()  {
    quit := make(chan bool)
    ch := make(chan string)

    go func() {
        for {
            select {
            case name := <-ch:
                fmt.Printf("from main msg: [%v]\n", name)
                if name == "bye" {
                    quit <- true
                } else {
                    quit <- false
                }
            }
        }
    }()

    for {
        // 控制台输入
        fmt.Print("please input string: ")
        scanner := bufio.NewScanner(os.Stdin)
        scanner.Scan()
        ch <- scanner.Text()

        isOver := <- quit
        if isOver {
            break
        }
    }
    fmt.Println("main over")
}

运行:

from main msg: [aaa]
please input string: bbb
from main msg: [bbb]
please input string: bye
from main msg: [bye]
main over

(2)超时实现

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

    go func() {
        for {
            select {
            case num := <- ch:
                fmt.Println("num = ", num)
            case <- time.After(5 * time.Second):
                fmt.Println("超时")
                quit <- true
            }
        }
    }()

    for i := 0; i < 2; i++ {
        ch <- i
        time.Sleep(time.Second)
    }
    <- quit                   // 等待超时后, 结束 main主线程
    fmt.Println("程序结束")
}

到此这篇关于go语言中如何使用select的实现示例的文章就介绍到这了,更多相关go语言使用select内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Go语言使用select{}阻塞main函数介绍

    很多时候我们需要让main函数不退出,让它在后台一直执行,例如: func main() { for i := 0; i < 20; i++ { //启动20个协程处理消息队列中的消息 c := consumer.New() go c.Start() } select {} // 阻塞 } 可能大多数人想到阻塞的方法是用channel,当然都是可以的,不过用select{}更加简洁 :) 补充:由浅入深聊聊Golang中select的实现机制 正文 话说今天在玩select的时候发现一个问题,是

  • 简介Go语言中的select语句的用法

    在Go编程语言中的select语句的语法如下: 复制代码 代码如下: select {     case communication clause  :        statement(s);          case communication clause  :        statement(s);     /* you can have any number of case statements */     default : /* Optional */        stat

  • go语言编程之select信道处理示例详解

    目录 select信道处理 fibonacci数列监听 select监听协程 select信道处理 注意:有default就不会阻塞 package main func main() { var chan1 = make(chan int) var chan2 = make(chan int) select { case <-chan1: // 如果chan1成功读到数据,则进行该case处理语句 case chan2: // 如果chan2成功读到数据,则进行该case处理语句 default

  • Go语言中Select语句用法实例

    本文实例讲述了Go语言中Select语句用法.分享给大家供大家参考.具体分析如下: select 语句使得一个 goroutine 在多个通讯操作上等待. select 会阻塞,直到条件分支中的某个可以继续执行,这时就会执行那个条件分支.当多个都准备好的时候,会随机选择一个. 复制代码 代码如下: package main import "fmt" func fibonacci(c, quit chan int) {         x, y := 1, 1         for {

  • go语言中如何使用select的实现示例

    目录 1.基本语法 2.select语句的实际应用 在golang语言中,select语句 就是用来监听和channel有关的IO操作,当IO操作发生时,触发相应的case动作. 有了 select语句,可以实现 main主线程 与 goroutine线程 之间的互动. 1.基本语法 select { case <-ch1 : // 检测有没有数据可读 // 一旦成功读取到数据,则进行该case处理语句 case ch2 <- 1 : // 检测有没有数据可写 // 一旦成功向ch2写入数据,

  • C语言中可变参数的使用方法示例

    前言 在C语言程序编写中我们使用最多的函数一定包括printf以及很多类似的变形体.这个函数包含在C库函数中,定义为 int printf( const char* format, ...); 除了一个格式化字符串之外还可以输入多个可变参量,如: printf("%d",i); printf("%s",s); printf("the number is %d ,string is:%s", i, s); 格式化字符串的判断本章暂且不论,下面分析一

  • C语言中变参函数传参的实现示例

    目录 背景引入 问题分析 指针大小 参数位置排布 解决问题 额外的测试 总结 参考资料 背景引入 近期在看一本书,叫做<嵌入式C语言自我修养>,写的内容对我帮助很大,是一本好书.在第6章,GNU C编译器扩展语法精讲一节,这本书给出了一些变参函数的例子: //1.变参函数初体验 #include<stdio.h> void print_num(int count,...) { int *args; args = &count + 1; for(int i = 0;i <

  • GO语言中常见的排序算法使用示例

    目录 快排 冒泡 选择排序 插入排序 希尔排序 二分法查找 快排 package main import ( "fmt" "math/rand" "time" ) func main() { li:=[]int{1,3,5,2,4,6,9,7} left:=0 right:=len(li)-1 fmt.Println(quick_sort(li,left,right)) } func quick_sort(li []int, left,right

  • go语言中排序sort的使用方法示例

    前言 sort包中实现了3种基本的排序算法:插入排序.快排和堆排序.和其他语言中一样,这三种方式都是不公开的,他们只在sort包内部使用.所以用户在使用sort包进行排序时无需考虑使用那种排序方式,sort.Interface定义的三个方法:获取数据集合长度的Len()方法.比较两个元素大小的Less()方法和交换两个元素位置的Swap()方法,就可以顺利对数据集合进行排序.sort包会根据实际数据自动选择高效的排序算法. 已知一个的struct组成的数组,现在要按照数组中的一个字段排序.pyt

  • Go语言中的变量声明和赋值

    1.变量声明和赋值语法 Go语言中的变量声明使用关键字var,例如 复制代码 代码如下: var name string //声明变量 name = "tom" //给变量赋值 这边var是定义变量的关键字,name是变量名称,string是变量类型,=是赋值符号,tom是值.上面的程序分两步,第一步声明变量,第二步给变量赋值.也可以将两步合到一起. 复制代码 代码如下: var name string = "tom" 如果在声明时同时赋值,可以省略变量类型,Go语

  • MySQL中Update、select联用操作单表、多表,及视图与临时表的区别

    一.MySQL中使用从表A中取出数据来更新表B的内容 例如:要update表data中的一些列属性,但是修改属性的内容来源是来自表chanpin.SQL语言中不要显示的出现select关键字 update data d,chanpin c set d.zhulei=c.zhulei,d.xiaolei=c.xiaolei,d.fenxiang=c.fenxiang,d.zhuanye=c.zhuanye,d.jiliang=c.jiliang,d.gs=c.zgs,d.xzgs=c.zgs,d.

  • 深入理解 Go 语言中的 Context

    Hi,大家好,我是明哥. 在自己学习 Golang 的这段时间里,我写了详细的学习笔记放在我的个人微信公众号 <Go编程时光>,对于 Go 语言,我也算是个初学者,因此写的东西应该会比较适合刚接触的同学,如果你也是刚学习 Go 语言,不防关注一下,一起学习,一起成长. 我的在线博客:http://golang.iswbm.com 我的 Github:github.com/iswbm/GolangCodingTime 1. 什么是 Context? 在 Go 1.7 版本之前,context 还

  • 详解R语言中生存分析模型与时间依赖性ROC曲线可视化

    R语言简介 R是用于统计分析.绘图的语言和操作环境.R是属于GNU系统的一个自由.免费.源代码开放的软件,它是一个用于统计计算和统计制图的优秀工具. 人们通常使用接收者操作特征曲线(ROC)进行二元结果逻辑回归.但是,流行病学研究中感兴趣的结果通常是事件发生时间.使用随时间变化的时间依赖性ROC可以更全面地描述这种情况下的预测模型. 时间依赖性ROC定义 令 Mi为用于死亡率预测的基线(时间0)标量标记. 当随时间推移观察到结果时,其预测性能取决于评估时间 t.直观地说,在零时间测量的标记值应该

  • R语言中对数据框的列名重命名的实现

    报错类型 Error: All arguments must be named plyr中的rename和dplyr中的rename用法是不同的. plyr::rename rename(data, c(old=new)) dplyr::rename rename(data, new = old) Example 比如, 默认的是plyr的rename, 运行下面命令, 会报错: d <- data.frame(old1=1:3, old2=4:6, old3=7:9) d library(ti

随机推荐