【go语言】select多路选择

news2024/9/24 11:24:55

select基础知识

select 是 Go 语言中用于处理通道操作的控制结构,它类似于 switch 语句,但专门用于通道的选择。select 语句使得一个 goroutine 可以等待多个通道操作,当其中任意一个通道操作可以进行时,就会执行相应的 case 分支。

select语句语法如下:

select {
case channel1 <- value1:
    // 如果 channel1 可以写入,执行这里
case value2 := <-channel2:
    // 如果 channel2 可以读取,执行这里
case value3, ok := <-channel3:
    // 如果 channel3 被关闭,并且有数据可读,执行这里
case <-time.After(time.Second):
    // 在超时时间内没有任何 case 可执行,执行这里
default:
    // 如果没有任何 case 可执行,执行这里
}

特性: 

  1. 如果多个 case 同时满足条件,Go 会随机选择一个执行。
  2. 如果没有 case 可以执行,且存在 default 分支,则执行 default
  3. 如果没有 default 分支,select 会阻塞,直到至少有一个 case 可执行。
  4. select 可以和 for 循环一起使用,用于不断地处理通道操作。

select 的主要用途是处理并发编程中的多个通道操作,例如处理超时、非阻塞通信等场景。

1. 超时控制

超时会比程序请求失败还可怕,为了避免主线程阻塞可以在select中设置超时中断。

示例代码如下:通过多路选择等待任务完成,如果超时就直接执行其他的处理程序

package main

import (
	"fmt"
	"time"
)

// 超时控制
func main() {
	select {
	case re := <-AsynService():
		fmt.Print("任务完成", re)
	case <-time.After(time.Millisecond * 3000):
		fmt.Print("超时啦")
		//default:
		//	fmt.Print("不能阻塞")
	}

}

// 服务
func service() string {
	time.Sleep(time.Millisecond * 3000)
	return "finish"
}

// 异步启动服务
func AsynService() chan string {
	rechan := make(chan string, 1)
	go func() {
		res := service()
		time.Sleep(time.Millisecond * 1000)
		rechan <- res
	}()
	return rechan
}

2. 任务取消

(1)获取取消通知

// 3.select判断任务是否取消
func isCanceled(cn chan struct{}) bool {
	select {
	case <-cn:
		fmt.Println("任务取消")
		return true
	default:
		fmt.Println("任务不取消,继续执行")
		return false
	}
}

(2)发送取消消息

// 1.普通向cancel通道发送取消通知,这种做法需要事先知道有多少个正在执行的任务
func cancel1(cn chan struct{}) {
	cn <- struct{}{}
}

// 2.向采取close方法关闭所有任务
func cancel2(cn chan struct{}) {
	close(cn)
}

(3)测试

// 测试任务取消
func TestCancel(t *testing.T) {
	cn := make(chan struct{})
	for i := 1; i < 6; i++ {
		go func(cn chan struct{}) {
			for {
				if isCanceled(cn) {
					break
				} else {
					time.Sleep(time.Millisecond * 1000)
				}
			}
			fmt.Println("任务取消")
		}(cn)
	}
	cancel2(cn)

}

六个go程进行监听任务是否取消,普通发送取消通知只会取消一个go程,关闭通道可以取消所有在监听的go程。

3. Context任务取消

(1)Context介绍

在 Go 语言中,context.Context 是一个标准库中非常常用的接口,它提供了在多个 goroutine 之间传递请求范围的截止日期、取消信号、存储值等信息的途径。context.Context 主要用于在函数之间传递请求的截止日期、取消信号、跟踪信息以及其他请求范围的值。

type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() <-chan struct{}
    Err() error
    Value(key interface{}) interface{}
}
  • Deadline():返回 Context 的截止日期(即取消的时间点)和一个布尔值,表示是否设置了截止日期。
  • Done():返回一个 <-chan struct{} 类型的通道,该通道关闭时表示 Context 被取消或者达到了截止日期。
  • Err():返回一个错误,表示 Context 被取消的原因。
  • Value(key interface{}):根据给定的键返回相关联的值,通常用于传递请求范围的值。

context 包还提供了一些函数用于创建和操作 Context

  • context.Background():返回一个空的 Context,常用于表示整个请求生命周期。
  • context.TODO()TODO 表示 "to do",返回一个空的、不可取消的 Context
  • context.WithCancel(parent Context) (ctx Context, cancel CancelFunc):返回一个可取消的 Context 和一个对应的 CancelFunc,可以用来取消该 Context
  • context.WithDeadline(parent Context, d time.Time) (Context, CancelFunc):返回一个带有截止日期的 Context
  • context.WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc):返回一个带有超时时间的 Context
  • context.WithValue(parent Context, key, val interface{}) Context:返回一个包含指定键值对的 Context

(2)任务取消

发送取消消息:

func isCanceled2(ctx context.Context) bool {
	select {
	case <-ctx.Done():
		return true
	default:
		return false
	}
}

我们可以看一下ctx.Done()的源码:

Done()方法返回一个channel,直接读取这个channel将会被阻塞,让我们看一下cancelCtx源码:

由上面的结构体可以知道这里c.done是一个原子操作的值,采用懒加载方法,被第一次调用的cancel方法关闭。
调用Done函数时已经存在一个取消通道时就直接返回,当是第一个调用的就创建channel并返回,都是并发安全的。

测试:

func TestContextCancel(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	for i := 1; i < 6; i++ {
		go func(i int, ctx context.Context) {
			for {
				if isCanceled2(ctx) {
					break
				} else {
					time.Sleep(time.Millisecond * 100)
				}
			}
			fmt.Println(i, "Cancelled")
		}(i, ctx)
	}
	cancel()
	time.Sleep(time.Second * 1)
}

这里通过context.Background()函数获得顶级context,通过WithCancel函数获取一个子上下文和一个取消函数,通过取消顶级context可以取消所有子上下文达到任务取消目的,或者是子上下文其自身取消。

 让我们看一下cancel方法:cancel方法关闭c.done也就是关闭了这个chan通道通知任务取消,同时也递归取消所有的子上下文,如果removeFromParent参数为true将会从父context移除掉当前子context。

// cancel closes c.done, cancels each of c's children, and, if
// removeFromParent is true, removes c from its parent's children.
// cancel sets c.cause to cause if this is the first time c is canceled.
func (c *cancelCtx) cancel(removeFromParent bool, err, cause error) {
	if err == nil {
		panic("context: internal error: missing cancel error")
	}
	if cause == nil {
		cause = err
	}
	c.mu.Lock()
	if c.err != nil {
		c.mu.Unlock()
		return // already canceled
	}
	c.err = err
	c.cause = cause
	d, _ := c.done.Load().(chan struct{})
	if d == nil {
		c.done.Store(closedchan)
	} else {
		close(d)
	}
	for child := range c.children {
		// NOTE: acquiring the child's lock while holding parent's lock.
		child.cancel(false, err, cause)
	}
	c.children = nil
	c.mu.Unlock()

	if removeFromParent {
		removeChild(c.Context, c)
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1360264.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TS学习笔记一:认识TS及环境准备

本次学习笔记是具有一定js基础的情况下从头开始学习ts相关内容。 视频信息 TS学习笔记一&#xff1a;认识TS及环境准备 B站视频 TS学习笔记一&#xff1a;认识TS及环境准备 西瓜视频 https://www.ixigua.com/7320049274006274560 1.1.目的 通过本次学习&#xff0c;学习并…

Linux第13步_安装“vim编辑器”及应用介绍

学习“磁盘重新分区”后&#xff0c;嵌入式Linux系统环境搭建进入安装“vim编辑器”这个环节。vim编辑器可以用来修改文件&#xff0c;在后期使用中&#xff0c;会经常用到。 1、安装“vim编辑器” 输入“sudo apt-get install vim回车”&#xff0c;就可以执行安装“vim编辑…

【AI视野·今日Sound 声学论文速览 第三十七期】Tue, 31 Oct 2023

AI视野今日CS.Sound 声学论文速览 Tue, 31 Oct 2023 Totally 11 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Sound Papers DCHT: Deep Complex Hybrid Transformer for Speech Enhancement Authors Jialu Li, Junhui Li, Pu Wang, Youshan Zhang当前大多数基于深…

运维系列:此站点的连接不安全,使用不受支持的协议。ERR_SSL_VERSION_OR_CIPHER_MISMATCH(不支持的协议 客户端和服务器不支持常用的 SSL 协议版本或密码套件。)

此站点的连接不安全&#xff0c;使用不受支持的协议。ERR_SSL_VERSION_OR_CIPHER_MISMATCH&#xff08;不支持的协议 客户端和服务器不支持常用的 SSL 协议版本或密码套件。&#xff09; 前言一、解决方法一1.Microsoft Edge浏览器→点击右上角的三个点→选择设置2.选择外观→打…

【代码随想录】刷题笔记Day46

前言 刚考完自辩&#xff0c;Chat回答举例什么的真方便。早上做组会PPT去了&#xff0c;火速来刷题&#xff01; 139. 单词拆分 - 力扣&#xff08;LeetCode&#xff09; 单词是物品&#xff0c;字符串s是背包&#xff0c;单词能否组成字符串s&#xff0c;就是问物品能不能把…

智云影院CMS程序PHP源码V3.0 无需数据库

本程序无需数据库&#xff0c;直接上传源码即可访问&#xff0c;&#xff08;服务器或虚拟主机空间&#xff09;都可以搭建使用&#xff01;模板自适应端&#xff0c;浏览体验更佳&#xff01;安装操作简单&#xff01;无需繁琐的操作&#xff0c;即可快速拥有一个视频看片资源…

transforms图像增强(一)

一、数据增强 数据增强&#xff08;Data Augmentation&#xff09;是一种常用的数据预处理技术&#xff0c;通过对训练集进行各种变换和扩增操作&#xff0c;可以增加训练数据的多样性和丰富性&#xff0c;从而提高模型的泛化能力。 数据增强的目的是通过对训练集中的图像进行…

JVM工作原理与实战(七):类的生命周期-初始化阶段

专栏导航 JVM工作原理与实战 RabbitMQ入门指南 从零开始了解大数据 目录 专栏导航 前言 一、类的生命周期 1.加载&#xff08;Loading&#xff09; 2.连接&#xff08;Linking&#xff09; 3.初始化&#xff08;Initialization&#xff09; 4.使用&#xff08;Using&…

面试算法96:字符串交织

题目 输入3个字符串s1、s2和s3&#xff0c;请判断字符串s3能不能由字符串s1和s2交织而成&#xff0c;即字符串s3的所有字符都是字符串s1或s2中的字符&#xff0c;字符串s1和s2中的字符都将出现在字符串s3中且相对位置不变。例如&#xff0c;字符串"aadbbcbcac"可以由…

使用 Kafka 和 CDC 将数据从 MongoDB Atlas 流式传输到 SingleStore Kai

SingleStore 提供了变更数据捕获 (CDC) 解决方案&#xff0c;可将数据从 MongoDB 流式传输到 SingleStore Kai。在本文中&#xff0c;我们将了解如何将 Apache Kafka 代理连接到 MongoDB Atlas&#xff0c;然后使用 CDC 解决方案将数据从 MongoDB Atlas 流式传输到 SingleStore…

SparkStreaming基础解析(四)

1、 Spark Streaming概述 1.1 Spark Streaming是什么 Spark Streaming用于流式数据的处理。Spark Streaming支持的数据输入源很多&#xff0c;例如&#xff1a;Kafka、Flume、Twitter、ZeroMQ和简单的TCP套接字等等。数据输入后可以用Spark的高度抽象原语如&#xff1a;map、…

网络调试 UDP1,开发板用静态地址-入门5

https://www.bilibili.com/video/BV1zx411d7eC?p11&vd_source109fb20ee1f39e5212cd7a443a0286c5 1, 开发板连接路由器 1.1&#xff0c;烧录无OS UDP例程 1.2&#xff0c;Mini USB连接电脑 1.3&#xff0c;开发板LAN接口连接路由器 2. Ping开发板与电脑之间通信* 2.1 根据…

Redis 教程

Redis 简介 Redis 是完全开源的&#xff0c;遵守 BSD 协议&#xff0c;是一个高性能的 key-value 数据库。 Redis 与其他 key - value 缓存产品有以下三个特点&#xff1a; Redis支持数据的持久化&#xff0c;可以将内存中的数据保存在磁盘中&#xff0c;重启的时候可以再次…

智能分析网关V4太阳能风光互补远程视频智能监控方案

一、背景需求 在一些偏远地区&#xff0c;也具有视频监控的需求。但是这类场景中&#xff0c;一般无法就近获取市电&#xff0c;如果要长距离拉取市电&#xff0c;建设的成本非常高且长距离传输有安全隐患&#xff0c;因此风光互补远程视频监控方案的需求也较多。利用风光电转化…

Reids在Win下无法远程访问

1.将redis在windows上启动主要做了以下配置 1.1.在redis.windows.conf中修改一下 原&#xff1a;bind 127.0.0.1 改&#xff1a;# bind 127.0.0.1 bind 0.0.0.0 原&#xff1a;protected-mode yes 改&#xff1a;protected-mode no去掉了127.0.0.1&#xff0c;加入0.0.0.0后&…

[C#]winform部署PaddleDetection的yolo印章检测模型

【官方框架地址】 https://github.com/PaddlePaddle/PaddleDetection.git 【算法介绍】 PaddleDetection 是一个基于 PaddlePaddle&#xff08;飞桨&#xff09;深度学习框架的开源目标检测工具库。它提供了一系列先进的目标检测算法&#xff0c;包括但不限于 Faster R-CNN, …

C ++类

定义一个Person类&#xff0c;私有成员int age&#xff0c;string &name&#xff0c;定义一个Stu类&#xff0c;包含私有成员double *score&#xff0c;写出两个类的构造函数、析构函数、拷贝构造和拷贝赋值函数&#xff0c;完成对Person的运算符重载(算术运算符、条件运算…

Linux———cat命令详解

目录 cat 命令是 Linux 中用于查看文件的内容或将多个文件合并输出。 基本语法&#xff1a; 常用选项&#xff1a; 示例用法&#xff1a; 查看文件的内容&#xff1a; ​编辑 将多个文件的内容合并输出&#xff1a; ​编辑 显示每一行的行号&#xff1a; ​编辑 显示非…

使用CentOS 7.6搭建HTTP隧道代理服务器

在现代网络环境中&#xff0c;HTTP隧道代理服务器因其灵活性和安全性而受到广泛关注。CentOS 7.6&#xff0c;作为一个稳定且功能强大的Linux发行版&#xff0c;为搭建此类服务器提供了坚实的基础。 首先&#xff0c;我们需要明确HTTP隧道代理的基本原理。HTTP隧道代理允许客户…

为什么云性能监控如此重要?

在当今数字化时代&#xff0c;企业越来越依赖云服务来支持其业务需求。为了确保云服务的可用性、性能和稳定性&#xff0c;云性能监控成为管理和优化云基础架构的关键一环。那么&#xff0c;为什么云性能监控如此重要?下面&#xff0c;就来看看具体介绍吧! 一、实时故障检测 云…