自学内容网 自学内容网

【go 】 select case 的用法


相关文章:
【go】select 语句case的随机性
【go】 select case 超时机制(time.After)示例和内存泄漏

1. 基本使用:监听多个通道,会阻塞

特点:
1)case 只能一次性的,一旦响应后,就结束了,参见后面第三章节for的例子,可以多次监听
2)如果多个通道都没有响应,会阻塞,直到某个通道率先响应

package main

import (
"fmt"
"time"
)

func main() {
ch1 := make(chan string)
ch2 := make(chan string)

// 启动两个 goroutine 发送数据
go func() {
time.Sleep(2 * time.Second)
ch1 <- "Message from ch1"
}()

go func() {
time.Sleep(1 * time.Second)
ch2 <- "Message from ch2"
}()

// 使用 select 等待任意一个通道的消息
select {
case msg1 := <-ch1:
fmt.Println("Received:", msg1)
case msg2 := <-ch2:
fmt.Println("Received:", msg2)
}
}


输出示例:


Received: Message from ch2

2.带默认分支:非阻塞操作

select 可以配合 default 分支进行非阻塞操作。

当其他的case不满足条件时,就一定会走到default分支,不会阻塞


package main

import "fmt"

func main() {
ch := make(chan string)

select {
case msg := <-ch:
fmt.Println("Received:", msg)
default:
fmt.Println("No message received, doing something else...")
}
}

输出:

No message received, doing something else...

3. 永远监听多个通道

用 for-select 模式可以实现对多个通道的持续监听。


package main

import (
"fmt"
"time"
)

/*
*
模拟一直监听
*/
func main() {
ch1 := make(chan string)
ch2 := make(chan string)

go func() {
for {
time.Sleep(2 * time.Second)
ch1 <- "Ping"
}
}()

go func() {
for {
time.Sleep(3 * time.Second)
ch2 <- "Pong"
}
}()

for {
select {
case msg := <-ch1:
fmt.Println("Received from ch1:", msg)
case msg := <-ch2:
fmt.Println("Received from ch2:", msg)
}
}
}

4. 超时机制

详情参见 【go】 select case 超时机制(time.After)示例和内存泄漏

配合 time.After 可以实现超时控制。


package main

import (
"fmt"
"time"
)

func main() {
ch := make(chan string)

// 启动一个 goroutine,模拟长时间处理
go func() {
time.Sleep(3 * time.Second)
ch <- "Result"
}()

select {
case res := <-ch:
fmt.Println("Received:", res)
case <-time.After(2 * time.Second):
fmt.Println("Timeout!")
}
}

输出:

Timeout!

5. 关闭通道的处理

当通道关闭时,select 中接收操作会立即返回零值。

注意:当通道被关闭后,不是阻塞的,而是立即返回一个0值。 这里的0值是指长度为0的字符串,不是数字0


package main

import "fmt"

func main() {
ch := make(chan int)
go func() {
ch <- 42
close(ch)
}()

select {
case val, ok := <-ch:
if !ok {     //利用ok来判断是否通道是关闭的
fmt.Println("Channel closed!")
} else {
fmt.Println("Received:", val)
}
}
}

6. context的关闭判断

有时候利用上下文,我们可以实现一些功能,并且需要判断上下文是否关闭,也可以通过select case



package main

import (
"context"
"fmt"
"time"
)

func worker(ctx context.Context, id int) {
select {
case <-ctx.Done():
fmt.Printf("Worker %d: canceled\n", id)
case <-time.After(2 * time.Second):
fmt.Printf("Worker %d: completed\n", id)
}
}

func main() {
// 创建父 context
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

// 子 context
subCtx1, cancel1 := context.WithTimeout(ctx, 1*time.Second)
defer cancel1()

subCtx2, cancel2 := context.WithTimeout(ctx, 3*time.Second)
defer cancel2()

go worker(subCtx1, 1)
go worker(subCtx2, 2)

// 模拟某种条件触发取消
time.Sleep(2 * time.Second)
cancel() // 取消父 context,影响所有子 context

time.Sleep(2 * time.Second)
fmt.Println("Main function exits")
}


原文地址:https://blog.csdn.net/m0_45406092/article/details/144259541

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!