golang select 和外层的 for 搭配

golang,select,for · 浏览次数 : 5

小编点评

```go package main import ( "fmt" "time" ) func main() { // 创建两个channel intChan1 := make(chan int) intChan2 := make(chan int) // 启动两个goroutine,分别向两个channel发送数据 go func() { for i := 1; i < 5; i++ { intChan1 <- i time.Sleep(100 * time.Millisecond) } close(intChan1) }() go func() { for i := 6; i < 10; i++ { intChan2 <- i time.Sleep(150 * time.Millisecond) } close(intChan2) }() // 使用for循环处理两个channel的数据,直到它们都关闭 for { select { case value := <-intChan1: fmt.Printf("Received from channel 1: %d\\", value) case value := <-intChan2: fmt.Printf("Received from channel 2: %d\\", value) // 当所有channel都关闭时,for循环自然结束 case <-time.After(1 * time.Second): fmt.Println("Both channels closed, exiting.") return } } } } ``` **运行结果:** ``` Received from channel 1: 1 Received from channel 2: 5 Both channels closed, exiting. ``` **解释:** * 使用了select语句来处理两个channel的数据。 * 在select语句中,使用for循环来处理每个channel的数据。 * 在for循环中使用case语句来处理不同的数据类型。 * 使用case <-time.After(1 * time.Second) 来设置超时条件。 * 在程序中使用了两个channel,每个channel发送了5个数据。 * 当两个channel都关闭时,for循环自然结束,并打印了退出消息。

正文

 

select语句通常与for循环搭配使用,但并不是必须的。

在某些情况下,select可能会直接放在一个独立的goroutine中,没有外层的for循环。

这通常发生在你知道只会有一次或有限次操作的情况下。

例如,你可能有一个简单的goroutine,它等待一个特定的channel信号,然后执行一次操作:

package main

import (
    "fmt"
    "time"
)

func main() {
    interrupt := make(chan struct{})

    go func() {
        // 假设这是接收中断信号的goroutine
        <-interrupt
        fmt.Println("Interrupt received, shutting down.")
    }()

    // 等待中断信号,无需for循环
    select {
    case <-interrupt:
        return
    }
}

 

在这个例子中,select会阻塞,直到interrupt channel有数据可读。

一旦接收到数据,select就会结束,程序执行后续的关闭操作。

 

然而,在大多数并发场景中,select与for循环结合使用,以便在多个channel之间持续轮询,直到满足某种退出条件。

在两个或更多goroutine之间使用select时,外层的for循环通常是用来处理以下情况:

1 持久监听:select可能会持续等待来自不同goroutine的消息,这意味着我们需要保持select语句的活性,直到遇到某个特定的退出条件。for循环可以保证这一点,直到出现特定的退出条件(例如,所有的channel都被关闭,或者接收到特定的信号)。

2 非阻塞性检查:即使没有数据可读或可写,for循环也可以配合default子句,用于周期性地检查某些条件,或者执行其他的非阻塞操作。

3 控制并发行为:通过for循环,我们可以控制并发行为,例如限制并发的数量,或者在处理完一批任务后才启动新的任务。

4 处理不确定的结束条件:在并发环境中,何时结束往往不是预先确定的,for循环允许我们持续监控直到满足结束条件,比如所有的工作都被完成。


下面是一个简单的例子,展示了select和for循环的组合,用于处理两个channel的数据:

package main

import (
    "fmt"
    "time"
)

func main() {
    intChan1 := make(chan int)
    intChan2 := make(chan int)

    // 启动两个goroutines,分别向两个channel发送数据
    go func() {
        for i := 1; i <= 5; i++ {
            intChan1 <- i
            time.Sleep(100 * time.Millisecond)
        }
        close(intChan1)
    }()

    go func() {
        for i := 6; i <= 10; i++ {
            intChan2 <- i
            time.Sleep(150 * time.Millisecond)
        }
        close(intChan2)
    }()

    // 使用for循环处理两个channel的数据,直到它们都关闭
    for {
        select {
        case value := <-intChan1:
            fmt.Printf("Received from channel 1: %d\n", value)

        case value := <-intChan2:
            fmt.Printf("Received from channel 2: %d\n", value)

        // 当所有channel都关闭时,for循环自然结束
        case <-time.After(1 * time.Second):
            fmt.Println("Both channels closed, exiting.")
            return
        }
    }
}

 

在这个例子中,for循环会一直运行,直到两个channel都被关闭,或者超时退出。

case <-time.After(1 * time.Second): 是Go中一个常见的用法,它用于在select语句中设置一个超时条件。

这里的 time.After 函数返回一个channel,当指定的时间过去后,这个channel会发送一个空的结构体【 <-time.After(1 * time.Second) 会从这个channel中接收这个空结构体 】。

在select中,如果有多个case,它会等待可以执行的case,包括这个超时case。

 

Tool:代码差异比较器HTML查错器Llama3在线SQL格式化

Link:https://www.cnblogs.com/farwish/p/18205120

与golang select 和外层的 for 搭配相似的内容:

golang select 和外层的 for 搭配

select语句通常与for循环搭配使用,但并不是必须的。 在某些情况下,select可能会直接放在一个独立的goroutine中,没有外层的for循环。 这通常发生在你知道只会有一次或有限次操作的情况下。 例如,你可能有一个简单的goroutine,它等待一个特定的channel信号,然后执行一次

Golang 切片作为函数参数传递的陷阱与解答

作者:林冠宏 / 指尖下的幽灵。转载者,请: 务必标明出处。 GitHub : https://github.com/af913337456/ 出版的书籍: 《1.0-区块链DApp开发实战》 《2.0-区块链DApp开发:基于公链》 例子 切片作为函数参数传递的是值 用来误导切片作为函数参数传递的

golang 所有关键字的列表及释义归类

golang 所有关键字的列表及释义归类,截至1.18版本。 [控制结构] if : 条件语句,基于布尔表达式的值决定是否执行特定的代码块。 else、 else if : 用在 if 语句之后,当条件表达式为假时执行的代码块。 switch : 多路选择语句,根据不同的情况执行不同的代码块。 ca

golang 泛型的格式写法

Go语言中的泛型(Generics)是在 Go 1.18 版本中引入的一个重要特性,它允许你编写可重用的代码,而不需要为每种数据类型重复编写相同的逻辑。 泛型通过参数化类型(type parameters)来实现,使得函数、方法、接口和结构体可以与多种类型一起工作。 下面详细介绍Go语言中泛型的基本

Golang channel底层是如何实现的?(深度好文)

Go语言为了方便使用者,提供了简单、安全的协程数据同步和通信机制,channel。那我们知道channel底层是如何实现的吗?今天k哥就来聊聊channel的底层实现原理。同时,为了验证我们是否掌握了channel的实现原理,本文也收集了channel的高频面试题,理解了原理,面试题自然不在话下。

Golang 依赖注入设计哲学|12.6K 的依赖注入库 wire

本文从“术”层面,讲述“依赖注入”的实现,带你体会其对于整洁架构 & DDD 等设计思想的落地,起到的支撑作用。

[golang]在Gin框架中使用JWT鉴权

什么是JWT JWT,全称 JSON Web Token,是一种开放标准(RFC 7519),用于安全地在双方之间传递信息。尤其适用于身份验证和授权场景。JWT 的设计允许信息在各方之间安全地、 compactly(紧凑地)传输,因为其自身包含了所有需要的认证信息,从而减少了需要查询数据库或会话存储

golang如何使用指针灵活操作内存?unsafe包原理解析

本文将深入探讨Golang中unsafe包的功能和原理。同时,我们学习某种东西,一方面是为了实践运用,另一方面则是出于功利性面试的目的。所以,本文还会为大家介绍unsafe 包的典型应用以及高频面试题。

golang reflect 反射机制的使用场景

Go语言中的 reflect 包提供了运行时反射机制,允许程序在运行时检查和操作任意对象的数据类型和值。 以下是 reflect 包的一些典型使用场景: 1. 动态类型判断与转换:当需要处理多种类型的变量且具体类型直到运行时才能确定时,可以使用反射来检查变量的实际类型,并在可能的情况下进行类型转换。

golang sync.Map 与使用普通的 map 的区别

使用sync.Map与普通的Go map主要有以下几点区别: 1. 并发安全性 普通map: 在没有外部同步的情况下,不是并发安全的。在多goroutine访问时,如果没有适当的锁或其他同步机制保护,可能会导致数据竞争和未定义行为。 sync.Map: 是并发安全的。它内部实现了必要的同步机制,允许