go的slice学习
并发访问slice
线上出现一粒多协程并发append全局slice的情况,导致内存不断翻倍,因此对slice的使用需要重新考虑。
并发读写的情况下, 可以利用锁、channel等避免竞态
问题
func TestDemo32(t *testing.T) {var wg sync.WaitGroupvar n = 100s := make([]int, 0, 200)hdr := (*reflect.SliceHeader)(unsafe.Pointer(&s))fmt.Printf("Data addr: %d\n", hdr.Data)fmt.Printf("Data cap: %d\n", hdr.Cap)fmt.Printf("Data len: %d\n", hdr.Len)wg.Add(n)for i := 1; i <= n; i++ {go func(v int) {defer wg.Done()s = append(s, v)}(i)}wg.Wait()hdr = (*reflect.SliceHeader)(unsafe.Pointer(&s))fmt.Printf("Data addr: %d\n", hdr.Data)fmt.Printf("Data cap: %d\n", hdr.Cap)fmt.Printf("Data len: %d\n", hdr.Len)fmt.Println(jsonx.ToString(s))// Data addr: 824645965056// Data cap: 200// Data len: 0// Data addr: 824645965056// Data cap: 200// Data len: 96
}func TestDemo33(t *testing.T) {var wg sync.WaitGroupvar n = 500s := make([]int, 0, 10)hdr := (*reflect.SliceHeader)(unsafe.Pointer(&s))fmt.Printf("Data addr: %d\n", hdr.Data)fmt.Printf("Data cap: %d\n", hdr.Cap)fmt.Printf("Data len: %d\n", hdr.Len)wg.Add(n)for i := 1; i <= n; i++ {go func(v int) {defer wg.Done()s = append(s, v)}(i)}wg.Wait()hdr = (*reflect.SliceHeader)(unsafe.Pointer(&s))fmt.Printf("Data addr: %d\n", hdr.Data)fmt.Printf("Data cap: %d\n", hdr.Cap)fmt.Printf("Data len: %d\n", hdr.Len)fmt.Println(jsonx.ToString(s))// Data addr: 824635459136// Data cap: 10// Data len: 0// Data addr: 824665328128// Data cap: 672// Data len: 453
}
Go语言中的slice是一种引用类型,它本身不保存任何元素,只是对数组的引用。
append操作的主要功能是向slice添加元素。
如果slice的底层数组容量足够,就直接添加;如果不够,就会先分配新的底层数组,然后将原有的元素和新添加的元素一起拷贝到新数组,在这个过程中,原有的底层数组会被垃圾回收。
当底层数组的容量不足以容纳新的元素时,就会产生新的底层数组
此时原有的slice和返回的新的slice,其底层数组是不同的。
这也是为什么在使用append时,总是习惯性地将结果再次赋值给原slice。
方案一 channel
func TestDemo(t *testing.T) {// 无缓冲,发送侧有数据,接收侧才执行// 用于做同步c := make(chan struct{})// new 了该 job 后,该 job 就开始准备从 channel 接收数据s := NewScheduleJob(n, func() { c <- struct{}{} })// 并发发送数据到channelvar wg sync.WaitGroupvar n = 1000wg.Add(n)for i := 0; i < n; i++ {go func(v int) {defer wg.Done()s.AddData(v)}(i)}// 等待上述多个协程将数据存入slicewg.Wait()// 发送完之后关闭channels.Close()// 阻塞在这里是等待NewScheduleJob执行结束<-c// 最终实现读写一致fmt.Println(len(s.data))
}type ServiceData struct {ch chan int // 用来同步的channeldata []int // 存储数据的slice
}// Schedule 从 channel 接收数据串行存入slice,直到ch关闭
func (s *ServiceData) Schedule() {for i := range s.ch {s.data = append(s.data, i)}
}// Close 关闭channel
func (s *ServiceData) Close() {close(s.ch)
}// AddData 发送数据到 channel
func (s *ServiceData) AddData(v int) {s.ch <- v
}func NewScheduleJob(size int, done func()) *ServiceData {s := &ServiceData{ch: make(chan int, size),data: make([]int, 0),}go func() {// 并发地 append 数据到 slice// Schedule 从 channel 接收数据串行存入slice,直到ch关闭s.Schedule()// 通知主协程继续执行done()}()return s
}
优点:逻辑复杂,适用于高并发场景
方案二 - 锁
func main() {slc := make([]int, 0, 1000)var wg sync.WaitGroupvar lock sync.Mutexfor i := 0; i < 1000; i++ {wg.Add(1)go func(a int) {defer wg.Done()lock.Lock()defer lock.Unlock()slc = append(slc, a)}(i)}wg.Wait()fmt.Println(len(slc))
}
优点:锁的逻辑重,适用于对性能要求不高的场景
学习文档
https://juejin.cn/post/6844904134592692231
相关文章:
go的slice学习
并发访问slice 线上出现一粒多协程并发append全局slice的情况,导致内存不断翻倍,因此对slice的使用需要重新考虑。 并发读写的情况下, 可以利用锁、channel等避免竞态 问题 func TestDemo32(t *testing.T) {var wg sync.WaitGroupvar n 1…...
软件设计师17--磁盘管理
软件设计师17--磁盘管理 考点1:存储管理 - 磁盘管理调度算法磁盘调度 - FCFS磁盘调度 - SSTF例题: 考点1:存储管理 - 磁盘管理 存取时间寻道时间等待时间,训导时间是指磁头移动到磁道所需的时间;等待时间为等待读写的扇…...
学点Java打小工——Day2Day3一点作业
1 猜数字(10次机会) 随机生成[1,1000]的一个数,输入你猜的数程序会给出反馈,直到猜对或次数用尽(10次)。 //猜数字 10次机会Testpublic void guessNumber() {Random random new Random();// [0, 1000) 1// [1, 1000]int num ra…...
【话题】2024年AI辅助研发趋势,有那些应用领域
大家好,我是全栈小5,欢迎阅读文章! 此篇是【话题达人】系列文章,这一次的话题是《2024年AI辅助研发趋势》 目录 背景概念实践医药领域汽车设计领域展望未来文章推荐 背景 随着人工智能技术的持续发展与突破,2024年AI辅…...
蓝桥杯——数组切分
数组切分 题目分析 这里要搞清楚一个点就是满足区间内数字是连续数字的区间有什么样的特点,既然数字连续重新排列后的数字为n,n1,n2,n3,n4,…nlen,则最大数字和最小数字之差恰好是区间长度减1,即nlen-nlen,同样因为下标也是连续…...
【机器学习】进阶学习:详细解析Sklearn中的MinMaxScaler---原理、应用、源码与注意事项
【机器学习】进阶学习:详细解析Sklearn中的MinMaxScaler—原理、应用、源码与注意事项 这篇文章的质量分达到了97分,虽然满分是100分,但已经相当接近完美了。请您耐心阅读,我相信您一定能从中获得不少宝贵的收获和启发~ …...
数据库是什么?数据库连接、管理与分析工具推荐
一、数据库是什么? 数据库是一种结构化的数据存储系统,用于有效地组织、存储和管理大量的数据。它是一个集中化的数据存储库,通常由一个或多个数据表组成,每个数据表包含多个行和列,用于存储特定类型的数据。数据表中…...
【C#算法实现】可见的山峰对数量
文章目录 前言一、题目要求二、算法设计及代码实现2.1 算法思想2.2 代码实现 前言 本文是【程序员代码面试指南(第二版)学习笔记】C#版算法实现系列之一,用C#实现了《程序员代码面试指南》(第二版)栈和队列中的可见的…...
Selenium 隐藏浏览器指纹特征的几种方式
文章转载于:https://mp.weixin.qq.com/s/sXRXwMDqekUHfU2SnL-PYg 我们使用 Selenium 对网页进行爬虫时,如果不做任何处理直接进行爬取,会导致很多特征是暴露的 对一些做了反爬的网站,做了特征检测,用来阻止一些恶意爬虫…...
k8s发布nacos-server,nodeport配置注意事项
k8s发布nacos-server注册不上问题 问题描述:分析过程: 问题描述: k8s发布nacos-server做服务公用使用,nodeport暴漏服务给客户端注册, nacos:端口 8848:30601 9848:30701 分析过程:…...
伪分布式Spark集群搭建
一、软件环境 软 件 版 本 安 装 包 VMware虚拟机 16 VMware-workstation-full-16.2.2-19200509.exe SSH连接工具 FinalShell Linux OS CentOS7.5 CentOS-7.5-x86_64-DVD-1804.iso JDK 1.8 jdk-8u161-linux-x64.tar.gz Spark 3.2.1 spark-3.2.1-bin-…...
Android 监听卫星导航系统状态及卫星测量数据变化
源码 package com.android.circlescalebar;import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import android.Manifest; import android.conte…...
鸿蒙培训开发:就业市场的新热点~
金三银四在即,随着春节假期结束,各行各业纷纷复工复产,2024年的春季招聘市场也迎来了火爆的局面。最近发布的《2024年春招市场行情周报(第一期)》显示,尽管整体就业市场仍处于人才饱和状态,但华…...
【C++】string的底层剖析以及模拟实现
一、字符串类的认识 C语言中,字符串是以\0结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数, 但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理&a…...
Unity的PICO项目基础环境搭建笔记(调试与构建应用篇)
文章目录 前言一、为设备开启开发者模式1、开启PICO VR一体机。前往设置>通用>关于本机>软件版本号2、一直点击 软件版本号 ,直到出现 开发者 选项3、进入 开发者模式,打开 USB调试,选择 文件传输 二、实时预览应用场景1、下载PC端的…...
电脑远程桌面选项变成灰色没办法勾选怎么办?
有些人在使用Windows系统自带的远程桌面工具时,会发现系统属性远程桌面选项卡中勾选启用“允许远程连接到此计算机”。 导致此问题出现的原因主要是由于组策略或者注册表设置错误造成的。 修复远程桌面选项变灰的两种方法! 方法一:设置本地组…...
2024.3.14
1.成员函数版本实现算术运算符的重载,全局函数版本实现算术运算符的重载 #include <iostream>using namespace std;class Room {friend const Room operator-(const Room &a,const Room &b); private:string a;int b; public:Room(){}Room(string a,int b):a(a)…...
chatGPT的耳朵!OpenAI的开源语音识别AI:Whisper !
语音识别是通用人工智能的重要一环!可以说是AI的耳朵! 它可以让机器理解人类的语音,并将其转换为文本或其他形式的输出。 语音识别的应用场景非常广泛,比如智能助理、语音搜索、语音翻译、语音输入等等。 然而,语音…...
C语言冒泡排序
冒泡排序是一种简单的排序算法,通过重复遍历要排序的数列,依次比较两个相邻的元素,如果它们的顺序错误则交换它们。这个过程会重复进行,直到没有相邻的元素需要交换,也就是数列已经排序完成。 冒泡排序的名字来源于其工…...
vue2 elementui 封装一个动态表单复杂组件
封装一个动态表单组件在 Vue 2 和 Element UI 中需要考虑到表单字段的动态添加、删除以及验证等复杂功能。下面是一个简单的例子,展示如何创建一个可以动态添加和删除字段的表单组件。 首先,你需要安装并引入 Element UI: bash 复制 npm in…...
【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error
在前端开发中,JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作(如 Promise、async/await 等),开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝(r…...
Linux中《基础IO》详细介绍
目录 理解"文件"狭义理解广义理解文件操作的归类认知系统角度文件类别 回顾C文件接口打开文件写文件读文件稍作修改,实现简单cat命令 输出信息到显示器,你有哪些方法stdin & stdout & stderr打开文件的方式 系统⽂件I/O⼀种传递标志位…...
