go切片的深入学习以及context库的使用

news2024/9/20 5:41:03

Go切片专项学习

go切片扩容机制

go1.18 之前:

1.如果期望容量大于当前容量的两倍就会使用期望容量;
2.如果当前切片的长度小于 1024 就会将容量翻倍;
3.如果当前切片的长度大于 1024 就会每次增加 25% 的容量,直到新容量大于期望容量;

go1.18 之后:

1.如果期望容量大于当前容量的两倍就会使用期望容量;
2.如果当前切片的长度小于阈值(默认 256)就会将容量翻倍;
3.如果当前切片的长度大于等于阈值(默认 256),就会每次增加 25% 的容量,基准是 newcap + 3*threshold,直到新容量大于期望容量;

第一条相同,新扩容机制在长度小于256以下时,扩容机制仍然和旧的一样,不同的是,当大于256的时候扩容会按照指定的公式进行扩容。image-20240803154820757

image-20240803154722237

最后求极限扩容系数会趋近于1.25。

这样做的目的是为了控制让小的切片容量增长速度快一点,减少内存分配次数,而让大切片容量增长率小一点,更好地节省内存。

前几天朋友让我看了一道题:挺有意思的,短短几行代码就把切片的性质说的一清二楚。

package main

import "fmt"

func SliceRise(s []int) {
    s = append(s, 0)
    fmt.Printf("s = %v\n", s)
    for i := range s {
       s[i]++
    }
}

func main() {
    s1 := []int{1, 2}
    s2 := s1
    s2 = append(s2, 3)
    SliceRise(s1)
    SliceRise(s2)
    fmt.Printf("s1 = %v\n", s1)
    fmt.Printf("s2 = %v\n", s2)
}

这个代码输出结果是:

s = [1 2 0]
s = [1 2 3 0]
s1 = [1 2]   
s2 = [2 3 4] 

我们看看为什么?

首先,第一个s由于扩容,导致了底层数组改变,所以方法内和方法外是两个不同的结构,

第二个s在方法外就已经扩容了,进入方法内后底层数组指针仍然没有改变,这就是关键点了,既然没有改变,为什么内部是长度为4,外侧就为3了呢?

肯定会有很多人认为最后结果是2341 。

原因就在于切片是值传递的,传递进去的是原始切牌的拷贝,进入后新切片长度为4,容量为4,而在外侧的切片长度为3,容量为4,这就导致了只能输出前三位。

Context

Context 是 golang 中十分重要的接口,用于定义 goroutine 中的上下文信息,context 常用于以下几种情况:

  • 数据传递: 在多个 goroutine中传递数据
  • 超时管理: 通过配置超时时间,可以方便地配置协程的终止时间
  • 终止协程: 通过使用 cancel() 方法,协程可以很方便地终止,可以批量管理多个协程的终止
type Context interface {
    Deadline() (deadline time.Time, ok bool)       // 返回上下文的截止时间
    Done() <-chan struct{}                         // 返回一个只读的channel,用于通知上下文完成或取消
    Err() error                                    // 返回上下文的错误原因
    Value(key interface{}) interface{}             // 返回与key相关的值
}

(context接口定义了以上方法)context.Background():返回一个空的Context,通常作为根上下文使用,不带任何取消、超时或元数据。

ctx := context.Background()

context.TODO():返回一个空的Context,用于暂时没有上下文的地方,通常在开发中使用,需要在后续补充具体的上下文。

context.TODO():返回一个空的Context,用于暂时没有上下文的地方,通常在开发中使用,需要在后续补充具体的上下文。

context.WithTimeout(parent Context, timeout time.Duration):返回一个新的Context,带有一个超时。超时后,Done()通道会关闭,并且Err()方法返回context.DeadlineExceeded

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

context.WithCancel(parent Context):返回一个新的Context和一个取消函数。调用取消函数会取消这个上下文及其所有派生上下文。

ctx, cancel := context.WithCancel(context.Background())
defer cancel() // 确保在完成时调用取消函数

context.WithDeadline(parent Context, deadline time.Time):返回一个新的Context,带有一个截止时间。超过截止时间后,Done()通道会关闭,并且Err()方法返回context.DeadlineExceeded

deadline := time.Now().Add(5 * time.Second)
ctx, cancel := context.WithDeadline(context.Background(), deadline)
defer cancel()

context.WithValue(parent Context, key, value interface{}):返回一个新的Context,带有值。值可以用于传递元数据或请求范围的数据。

ctx := context.WithValue(context.Background(), "key", "value")
value := ctx.Value("key")

在gin框架中我们经常会用到gin.Context这个方法,他和context.Context的主要区别是什么呢?

context.Context

  • 用于跨 goroutine 传递上下文信息。
  • 适用于处理超时、取消、传递请求范围的数据等。

gin.Context

  • 用于 Gin 框架中处理 HTTP 请求和响应。
  • 提供了处理请求参数、设置响应、存储数据等功能。

超时示例:

package main

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

func main() {
	// 创建一个带有超时的 context,超时时间为 3 秒
	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel() // 在 main 函数结束时取消 context

	// 启动一个 Goroutine 进行某些工作
	go doWork(ctx)

	// 等待工作完成
	select {
	case <-ctx.Done(): // 如果 context 超时或被取消
		fmt.Println("Main: work canceled or timed out")
	}
}

func doWork(ctx context.Context) {
	fmt.Println("Worker: started work")

	// 模拟工作过程,工作时间为 5 秒
	workDuration := 5 * time.Second
	select {
	case <-time.After(workDuration): // 工作完成
		fmt.Println("Worker: work completed")
	case <-ctx.Done(): // 如果收到 context 的取消信号
		fmt.Println("Worker: work canceled due to:", ctx.Err())
	}
}
## Context

`Context` 是 golang 中十分重要的接口,用于定义 `goroutine` 中的上下文信息,`context` 常用于以下几种情况:

- 数据传递: ==在多个 goroutine中传递数据==
- 超时管理: 通过配置超时时间,可以方便地配置协程的终止时间
- 终止协程: 通过使用 `cancel()` 方法,协程可以很方便地终止,可以批量管理多个协程的终止

```go
type Context interface {
    Deadline() (deadline time.Time, ok bool)       // 返回上下文的截止时间
    Done() <-chan struct{}                         // 返回一个只读的channel,用于通知上下文完成或取消
    Err() error                                    // 返回上下文的错误原因
    Value(key interface{}) interface{}             // 返回与key相关的值
}

(context接口定义了以上方法)context.Background():返回一个空的Context,通常作为根上下文使用,不带任何取消、超时或元数据。

ctx := context.Background()

context.TODO():返回一个空的Context,用于暂时没有上下文的地方,通常在开发中使用,需要在后续补充具体的上下文。

context.TODO():返回一个空的Context,用于暂时没有上下文的地方,通常在开发中使用,需要在后续补充具体的上下文。

context.WithTimeout(parent Context, timeout time.Duration):返回一个新的Context,带有一个超时。超时后,Done()通道会关闭,并且Err()方法返回context.DeadlineExceeded

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

context.WithCancel(parent Context):返回一个新的Context和一个取消函数。调用取消函数会取消这个上下文及其所有派生上下文。

ctx, cancel := context.WithCancel(context.Background())
defer cancel() // 确保在完成时调用取消函数

context.WithDeadline(parent Context, deadline time.Time):返回一个新的Context,带有一个截止时间。超过截止时间后,Done()通道会关闭,并且Err()方法返回context.DeadlineExceeded

deadline := time.Now().Add(5 * time.Second)
ctx, cancel := context.WithDeadline(context.Background(), deadline)
defer cancel()

context.WithValue(parent Context, key, value interface{}):返回一个新的Context,带有值。值可以用于传递元数据或请求范围的数据。

ctx := context.WithValue(context.Background(), "key", "value")
value := ctx.Value("key")

在gin框架中我们经常会用到gin.Context这个方法,他和context.Context的主要区别是什么呢?

context.Context

  • 用于跨 goroutine 传递上下文信息。
  • 适用于处理超时、取消、传递请求范围的数据等。

gin.Context

  • 用于 Gin 框架中处理 HTTP 请求和响应。
  • 提供了处理请求参数、设置响应、存储数据等功能。

超时示例:

package main

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

func main() {
	// 创建一个带有超时的 context,超时时间为 3 秒
	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel() // 在 main 函数结束时取消 context

	// 启动一个 Goroutine 进行某些工作
	go doWork(ctx)

	// 等待工作完成
	select {
	case <-ctx.Done(): // 如果 context 超时或被取消
		fmt.Println("Main: work canceled or timed out")
	}
}

func doWork(ctx context.Context) {
	fmt.Println("Worker: started work")

	// 模拟工作过程,工作时间为 5 秒
	workDuration := 5 * time.Second
	select {
	case <-time.After(workDuration): // 工作完成
		fmt.Println("Worker: work completed")
	case <-ctx.Done(): // 如果收到 context 的取消信号
		fmt.Println("Worker: work canceled due to:", ctx.Err())
	}
}



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

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

相关文章

JavaScript - 对象编程之详解DOM对象

1. 文档对象模型&#xff08;DOM&#xff09; HTML DOM全称为HTML Document Object Model&#xff0c;专门适用于HTML/XHTML文档的对象模型。可以将HTML DOM理解为网页的API&#xff0c;将网页中的各种元素都看作一个对象&#xff0c;从而使网页中的元素也可以被计算机语言获取…

git的简单学习

&#xff08;这个模块本来是会用的&#xff0c;但是了解并不是那么深入&#xff0c;因此需要继续学习一下&#xff09; 1.下载安装 下载网址&#xff1a;https://git-scm.com/download/win/ 一直next就可以了。 2.检查 winr&#xff1a;cmd &#xff08;不建议&#xff09;…

零基础Opencv学习(四)

一、查找并绘制轮廓 /// 载入原始图&#xff0c;必须以二值图模式载入cv::Mat image cv::imread("E:/OpencvStudyTest/4.png", cv::ImreadModes::IMREAD_GRAYSCALE);cv::imshow("image", image);/// 初始化结果图cv::Mat dstImage cv::Mat::zeros(image.…

005:VTK世界坐标系中的相机和物体

VTK医学图像处理---世界坐标系中的相机和物体 左侧是成像结果 右侧是世界坐标系中的相机与被观察物体 简介 上图右侧的图像是模拟的世界坐标系和世界坐标系中相机以及被观察物体&#xff1b; 左侧是在右侧世界坐标系中相机…

黑神话:游戏的诞生

&#x1f6f0; 前言 近期&#xff0c;国产 3A 大作《黑神话&#xff1a;悟空》给我们带来了一波惊喜。相信各位或多或少都有所了解。看见如此激动人心的产品我们除了欣喜&#xff0c;也不禁让我们思考起来游戏是如何实现的&#xff1f;我们能否开发一款属于自己的游戏&#xff…

3D 场景模拟 2D 碰撞玩法的方案

目录 方法概述顶点到平面的垂直投影求解最小降维 OBB主成分分析&#xff08;PCA&#xff09;协方差矩阵求矩阵特征值Jacobi 方法 OBB 拉伸方法 对于类似《密特罗德 生存恐惧》和《暗影火炬城》这样 3D 场景&#xff0c;但玩法还是 2D 卷轴动作平台跳跃&#xff08;类银河恶魔城…

[项目][CMP][Central Cache]详细讲解

目录 1.设计&结构2.申请内存3.释放内存4.框架 1.设计&结构 Central Cache也是一个哈希桶结构&#xff0c;它的哈希桶的映射关系跟Thread Cache是一样的不同的是它的每个哈希桶位置挂的是SpanList链表结构(带头双向循环链表)&#xff0c;不过每个映射桶下面的span中的大…

链式栈、队列

1、链式栈&#xff1a; 声明&#xff1a; #ifndef _STACK_H #define _STACK_H #include<stdlib.h>typedef int DataType;typedef struct snode //节点 {DataType data;struct snode *pnext; }SNode_t;typedef struct stack //链表 {SNode_t *ptop;int clen; }St…

Patlibc———更快捷的更换libc

起初是为了简化做pwn题目时&#xff0c;来回更换libc的麻烦&#xff0c;为了简化命令&#xff0c;弄了一个小脚本&#xff0c;可以加入到/usr/local/bin中&#xff0c;当作一个快捷指令&#x1f522; 这个写在了tools库&#xff08;git clone https://github.com/CH13hh/tools…

C++利用jsoncpp库实现写入和读取json文件(含中文处理)

C利用jsoncpp库实现写入和读取json文件 1 jsoncpp常用类1.1 Json::Value1.2 Json::Reader1.3 Json::Writer 2 json文件3 写json文件3.1 linux存储结果3.2 windows存储结果 3 读json文件4 读json字符串参考文章 在C中使用跨平台的开源库JsonCpp&#xff0c;实现json的序列化和反…

【有啥问啥】大模型应用中的哈希链推理任务

大模型应用中的哈希链推理任务 随着人工智能技术的快速发展&#xff0c;尤其是大模型&#xff08;如GPT、BERT、Vision Transformer等&#xff09;的广泛应用&#xff0c;确保数据处理和模型推理的透明性与安全性变得愈发重要。哈希链推理任务作为一种技术手段&#xff0c;能够…

会员营销如何利用JSON发送短信

在当今这个数字化时代&#xff0c;企业间的竞争日益激烈&#xff0c;如何高效地触达并维护用户群体&#xff0c;提升用户粘性和忠诚度&#xff0c;成为了每个企业都必须面对的重要课题。在众多营销手段中&#xff0c;会员营销因其精准性和个性化而备受青睐。而在会员营销的策略…

人工智能导论(上)

一、人工智能概述 人工智能这个基本概念的起源&#xff08;人工智能作为计算机科学的一个分支&#xff09; 很多应用研究领域都在人工智能的范畴里&#xff0c;比如机器人、语言识别、图像识别、自然语言处理和专家系统等等。更加通俗的说&#xff0c;人工智能是要让一部机器能…

传输层协议UDP

本篇将主要介绍 UDP 协议&#xff0c;介绍了有关 UDP 协议的报头、协议特点、UDP 协议在操作系统中的缓冲区、UDP 协议使用的注意事项&#xff0c;以及有关 UDP 的 Socket 编程程序&#xff0c;同时重点介绍了操作系统对于 UDP 协议报文的管理。 接着介绍了有关端口号的映射。 …

s3c2440---中断控制器

一、概述 S3C2440A 中的中断控制器接受来自 60 个中断源的请求。提供这些中断源的是内部外设&#xff0c;如 DMA 控制器、 UART、IIC 等等。 在这些中断源中&#xff0c;UARTn、AC97 和 EINTn 中断对于中断控制器而言是“或”关系。 当从内部外设和外部中断请求引脚收到多个中…

哲学概述2(马克)

三、哲学的基本问题 思维是主观的&#xff08;对应意识&#xff09; 存在是客观的&#xff0c;不以人的意志为转移&#xff08;对应物质&#xff09; 恩格斯说&#xff1a;“全部哲学&#xff0c;特别是近代哲学的重大的基本问题&#xff0c;是思维和存在的关系问题” 哲学的基…

HTML生日蛋糕

目录 写在前面 完整代码 代码分析 系列文章 写在最后 写在前面 HTML实现的生日蛋糕来喽&#xff0c;小编亲测&#xff0c;发给好友可以直接打开哦。在代码的第183行可以写下对朋友的祝福&#xff0c;快拿去送给你的好朋友吧&#xff01; 完整代码 <!DOCTYPE html>…

Python中的位运算-从入门到精通

你是否曾经好奇过计算机是如何在底层处理数据的?或者,你是否想知道为什么有些程序员总是津津乐道于位运算的强大?如果是,那么你来对地方了!今天,我们将深入探讨Python中的位运算,揭示它们的神奇之处,以及如何利用它们来优化你的代码。 目录 位运算:计算机的秘密语言为什么位…

JavaScript Web API入门day6

目录 1.正则表达式 1.1 什么是正则表达式 1.2 语法 1.3 元字符 1.3.1 边界符 1.3.2 量词 1.3.3 字符类 1.4 修饰符 1.5 案例 2.综合案例 2.1 小兔鲜页面注册 2.2 小兔鲜登录页面 2.3 小兔鲜首页页面 1.正则表达式 1.1 什么是正则表达式 正则表达式&#xff08;Re…

Chapter 12 Vue CLI脚手架组件化开发

欢迎大家订阅【Vue2Vue3】入门到实践 专栏&#xff0c;开启你的 Vue 学习之旅&#xff01; 文章目录 前言一、项目目录结构二、组件化开发1. 组件化2. Vue 组件的基本结构3. 依赖包less & less-loader 前言 组件化开发是Vue.js的核心理念之一&#xff0c;Vue CLI为开发者提…