【golang】select和channel
场景1:实现并发调用多个方法,有一个返回结果就都返回
思路:可以使用 select 语句结合通道来等待多个 goroutine 返回结果,一旦有 goroutine 返回结果,就立即处理该结果并结束程序。
/**
* @desc
* @date 2025/4/19
* @user yangshuo
*/
package main
import (
"fmt"
"time"
)
func https(resultChan chan string) {
// 模拟 HTTP 请求
// t := time.NewTicker(time.Duration(rand.Intn(5)+1) * time.Second)
time.Sleep(time.Duration(4+1) * time.Second)
resultChan <- "http"
println("1")
}
func redis(resultChan chan string) {
// 模拟 HTTP 请求
// t := time.NewTicker(time.Duration(rand.Intn(5)+1) * time.Second)
// <-t.C
time.Sleep(time.Duration(5+1) * time.Second)
resultChan <- "redis"
println("2")
}
func mysql(resultChan chan string) {
// 模拟 HTTP 请求
// t := time.NewTicker(time.Duration(rand.Intn(5)+1) * time.Second)
// <-t.C
time.Sleep(time.Duration(3+1) * time.Second)
resultChan <- "mysql"
println("3")
}
func main() {
resultChan := make(chan string)
defer close(resultChan)
go https(resultChan)
go mysql(resultChan)
go redis(resultChan)
for {
select {
case result := <-resultChan:
fmt.Println("返回结果:", result)
return
}
}
}
场景2:实现并发调用多个校验方法,有一个成功就返回成功,所有方法都失败就返回失败。
思路:与场景1不同的是,失败情况需要等待所有goroutine都执行完。
/**
* @desc
* @date 2025/4/20
* @user yangshuo
*/
package main
import (
"fmt"
"math/rand"
"time"
)
func validateFunc1() bool {
// 模拟验证逻辑
// 设置随机种子
return false
rand.Seed(time.Now().UnixNano())
// 生成随机数(0 或 1)
randomNum := rand.Intn(2)
// 根据随机数返回 true 或 false
result := randomNum == 1
fmt.Println(result)
return result
}
func validateFunc2() bool {
return false
// 设置随机种子
rand.Seed(time.Now().UnixNano())
// 生成随机数(0 或 1)
randomNum := rand.Intn(2)
// 根据随机数返回 true 或 false
result := randomNum == 1
fmt.Println(result)
return result
}
func validateFunc3() bool {
return false
// 模拟验证逻辑
// 设置随机种子
rand.Seed(time.Now().UnixNano())
// 生成随机数(0 或 1)
randomNum := rand.Intn(2)
// 根据随机数返回 true 或 false
result := randomNum == 1
fmt.Println(result)
return result
}
func main() {
// 定义验证函数
validateFuncs := []func() bool{validateFunc1, validateFunc2, validateFunc3}
// 使用 channel 通知是否有函数通过验证
passed := make(chan bool)
// 并发调用验证函数
for _, vf := range validateFuncs {
go func(fn func() bool) {
if fn() {
passed <- true
}
}(vf)
}
// 检查是否有函数通过验证
for range validateFuncs {
select {
case <-passed:
fmt.Println("Validation passed")
return
}
fmt.Println("Validation failed")
}
需要注意的是:当所有 goroutines 都未通过验证时,由于没有 goroutine 向 passed 通道发送消息,select 语句会一直阻塞等待消息,从而导致程序发生死锁。为了避免这种情况,可以加上default分支。
// 检查是否有函数通过验证
for range validateFuncs {
select {
case <-passed:
fmt.Println("Validation passed")
return
default:
}
}