go select的用法

 基础语法  2022-01-22  admin  832  1123

go select的用法 

select {
    case <-ch1:
        // 如果从 ch1 信道成功接收数据,则执行该分支代码
    case ch2 <- 1:
        // 如果成功向 ch2 信道成功发送数据,则执行该分支代码
    default:
        // 如果上面都没有成功,则进入 default 分支处理流程
}

可以看到select的语法结构有点类似于switch,但又有些不同。

select里的case后面并不带判断条件,而是一个信道的操作,不同于switch里的case,对于从其它语言转过来的开发者来说有些需要特别注意的地方。

golang 的 select 就是监听 IO 操作,当 IO 操作发生时,触发相应的动作每个case语句里必须是一个IO操作,确切的说,应该是一个面向channel的IO操作。

注:Go 语言的 select 语句借鉴自 Unix 的 select() 函数,在 Unix 中,可以通过调用 select() 函数来监控一系列的文件句柄,一旦其中一个文件句柄发生了 IO 动作,该 select() 调用就会被返回(C 语言中就是这么做的),后来该机制也被用于实现高并发的 Socket 服务器程序。Go 语言直接在语言级别支持 select关键字,用于处理并发编程中通道之间异步 IO 通信问题。

注意:如果 ch1 或者 ch2 信道都阻塞的话,就会立即进入 default 分支,并不会阻塞。但是如果没有 default 语句,则会阻塞直到某个信道操作成功为止。

  1. select语句只能用于信道的读写操作

  2. select中的case条件(非阻塞)是并发执行的,select会选择先操作成功的那个case条件去执行,如果多个同时返回,则随机选择一个执行,此时将无法保证执行顺序。对于阻塞的case语句会直到其中有信道可以操作,如果有多个信道可操作,会随机选择其中一个 case 执行

  3. 对于case条件语句中,如果存在信道值为nil的读写操作,则该分支将被忽略,可以理解为从select语句中删除了这个case语句

  4. 如果有超时条件语句,判断逻辑为如果在这个时间段内一直没有满足条件的case,则执行这个超时case。如果此段时间内出现了可操作的case,则直接执行这个case。一般用超时语句代替了default语句

  5. 对于空的select{},会引起死锁

  6. 对于for中的select{}, 也有可能会引起cpu占用过高的问题

package main

import (
	"fmt"
	"time"
)

func main() {
	//使用 select 可以解决从管道取数据的阻塞问题
	//1.定义一个管道 10 个数据 int
	intChan := make(chan int, 10)
	for i := 0; i < 10; i++ {
		intChan <- i
	}
	//2.定义一个管道 5 个数据 string
	stringChan := make(chan string, 5)

	for i := 0; i < 5; i++ {
		stringChan <- "hello" + fmt.Sprintf("%d", i)
	}
	//传统的方法在遍历管道时,如果不关闭会阻塞而导致 deadlock
	//问题,在实际开发中,可能不好确定什么关闭该管道. 可以使用 select 方式可以解决
	
	//label:
	for {
		select {
		//注意: 这里,如果 intChan 一直没有关闭,不会一直阻塞而 deadlock
		//,会自动到下一个 case 匹配
		case v := <-intChan:
			fmt.Printf("从 intChan 读取的数据%d\n", v)
			time.Sleep(time.Second)
		case v := <-stringChan:
			fmt.Printf("从 stringChan 读取的数据%s\n", v)
			time.Sleep(time.Second)
		default:
			fmt.Printf("都取不到了,可以加入逻辑\n")
			time.Sleep(time.Second)
			return
			//break label
		}
	}
}


如果文章对您有帮助,点击下方的广告,支持一下作者吧!

转载必须注明出处:

go select的用法 —— code.cent123.com

相关推荐


在go协程中共享资源需要加锁处理

在go协程中共享资源需要加锁处理packagemain import( &quot;fmt&quot; &quot;sync&quot; ) //创建一个互斥锁 varmutex=&amp;sync.Mutex{} //定义一个共享资源 varsharedResource=0 //定义一个等待组 varwg=sync.WaitGroup{} //定义一

go WaitGroup 的使用方法

在 Go 中,sync 包下的 WaitGroup 能有助于我们控制协程之间的同步。当需要等待一组协程都执行完各自任务后,才能继续后续逻辑。这种场景,就非常适合使用它。WaitGroup 提供三个 API。Add(delta int) 函数提供了 WaitGroup 的任务计数,delta 的值可以为正也可以为负,通常在添加任务时使用。Done() 函数其实就是 Add(-1),在任务完成时调用。

go 协程管理及传参处理

Go语言中的goroutine虽然相对于系统线程来说比较轻量级(初始栈大小仅2KB),(并且支持动态扩容),而正常采用java,c++等语言启用的线程一般都是内核态的占用的内存资源一般在4m左右,而假设我们的服务器CPU内存为4G,那么很明显才用的内核态线程的并发总数量也就是1024个,相反查看一下Go语言的协程则可以达到4*1024*1024/2=200w.这么一看就明白了为什么Go语言天生支持

go 协程示例:获取指定范围的质数

go 协程示例:获取指定范围的质数