go 并发 gorouting chan channel select Mutex sync.One

news2025/2/22 12:34:46

goroutine

// head: 前缀  index:是一个int的指针
func print(head string, index *int) {
    for i := 0; i < 5; i++ {
       // 指针对应的int ++
       *index++
       fmt.Println(*index, head, i)
       // 暂停1s
       time.Sleep(1 * time.Second)
    }
}

/*
Go 允许使用 go 语句开启一个新的运行期线程,即 goroutine
以一个不同的、新创建的 goroutine 来执行一个函数
同一个程序中的所有 goroutine 共享同一个地址空间。
*/
func main() {
    fmt.Println("main ...")
    index := 0
    go print("first", &index)
    go print("second", &index)
    time.Sleep(6 * time.Second)
    fmt.Println("success ...")
}

chan 一般用法

// 求和,并将数据放在channel中
func sum(arr []int, resultChan chan int) {
    if len(arr) <= 0 {
       resultChan <- 0
       return
    }

    var sum = 0
    for _, value := range arr {
       sum += value
    }

    fmt.Println(sum)

    // 将结果放在channel中
    resultChan <- sum
}

/*
channel 用于 goroutine之间进行通信
 1. 创建channel
    ch1 := make(chan 类型)  默认是没有缓冲区的
    ch2 := make(chan 类型, 缓存长度)
 2. 添加数据到channel中
    ch1 <- 123
 3. 从channel中获取数据
    var value = <- ch1

有无缓冲区区别:
1. 没有缓冲区 按照缓冲区为1来处理,即channel只能放一个数据
2. channel满了后就会阻塞,直到有空位才可以继续放入数据
3. 获取数据类似,阻塞到channel中有数据
*/
func main() {
    fmt.Println("main ...")
    // 创建一个没有缓冲区的channel
    resultChan := make(chan int)
    array1 := []int{10, 20, 30}
    array2 := []int{1, 2, 3}
    // 给两个数组求和并将结果放在channel中
    go sum(array1, resultChan)
    go sum(array2, resultChan)
    // 从channel中获取两个数据,打印到console
    fmt.Println(<-resultChan, <-resultChan)
    fmt.Println("continue ...")
    // 如果继续获取则会报错:fatal error: all goroutines are asleep - deadlock!
    // fmt.Println(<-resultChan)
    fmt.Println("success ...")
}

无缓冲区的chan只能结合goroutine使用

func main() {
    fmt.Println("main ...")
    // 创建一个没有缓冲区的channel
    resultChan := make(chan int)
    // chan 只能结合goroutine来使用,否则报错
    // fatal error: all goroutines are asleep - deadlock!
    resultChan <- 10
    fmt.Println(<-resultChan)
    fmt.Println("success ...")
}

有缓冲区的chan可直接赋值

func main() {
    fmt.Println("main ...")
    // 创建一个有缓冲区的channel
    ch := make(chan int, 2)
    ch <- 1
    ch <- 2
    fmt.Println(<-ch)
    fmt.Println(<-ch)
    fmt.Println("success ...")
}

for rang获取channel数据

func addData(ch chan int, len int) {
    for i := 0; i < len; i++ {
       ch <- i
    }
    // 如果不关闭,for val := range ch 会阻塞获取数据
    close(ch)
}

/*
  - 可以使用rang遍历channel,如果channel关闭则直接结束,否则会阻塞等待数据的输入
    for val := range ch
*/
func main() {
    fmt.Println("main ...")
    // 创建一个有缓冲区的channel
    len := 5
    ch := make(chan int, len)
    go addData(ch, len)
    for val := range ch {
       fmt.Println(val)
    }
    fmt.Println("success ...")
}

select **等待多个goroutine

select可以等待多个goroutine,会阻塞一直到某个case不在阻塞。

func print1(header string, ch1, ch2 chan int) {
    for i := 0; i < len; i++ {
       select {
          case val := <-ch1:
             fmt.Println(header, val)
             time.Sleep(time.Second)
          case ch2 <- i:
             // do nothing
       }
    }
}

func main() {
    fmt.Println("main ...")
    ch1 := make(chan int)
    ch2 := make(chan int)
    go print1("f1", ch1, ch2)
    go print1("f2", ch2, ch1)
    time.Sleep(6 * time.Second)
    fmt.Println("success ...")
}

WaitGroup等待所有goroutine完成

类似java中的CountDownLatch

// 不怎么理解为什么group要用指针
func work(index int, wg *sync.WaitGroup) {
    defer wg.Done()
    fmt.Println(index)
    time.Sleep(time.Second)
}

func main() {
    fmt.Println("main ...")

    var wg sync.WaitGroup
    for i := 0; i < 5; i++ {
       wg.Add(1)
       // 为什么要将wg的指针传过去
       go work(i, &wg)
    }

    // 阻塞到所有的goroutine完成后
    wg.Wait()

    fmt.Println("success ...")
}

并发锁Mutex

type ConcurrentMap struct {
    lock    sync.Mutex
    hashmap map[string]int
}

// 1. cm *ConcurrentMap 要传指针,否则操作的是副本
// 2. wg *sync.WaitGroup 这个也传指针,确保操作的是一个对象
func (cm *ConcurrentMap) inc(index int, key string, wg *sync.WaitGroup) {
    defer wg.Done()
    fmt.Println(index, "start")
    cm.lock.Lock()
    before := cm.hashmap[key]
    fmt.Println(index, "before", before)
    cm.hashmap[key] = cm.hashmap[key] + 1
    time.Sleep(time.Microsecond * 100)
    after := cm.hashmap[key]
    fmt.Println(index, "after", after)
    if before+1 != after {
       fmt.Println(index, "error >>>>>")
    }
    cm.lock.Unlock()
    fmt.Println(index, "end")
}

func main() {
    fmt.Println("main ...")

    cm := ConcurrentMap{hashmap: make(map[string]int)}
    var wg sync.WaitGroup
    for i := 0; i < 3; i++ {
       wg.Add(1)
       go cm.inc(i, "apple", &wg)
    }
    wg.Wait()
    fmt.Println("success ...", cm.hashmap["apple"])
}

RWMutex 读写锁子

参考:

https://www.jianshu.com/p/679041bdaa39

sync.Once 配置文件只加载一次

需求:获取配置文件,如果没有价值只就加载

写法1:

func initMap() {
    if hasInitMap {
       return
    }
    initMapLock.Lock()
    defer initMapLock.Unlock()
    if !hasInitMap {
       fmt.Println("init map")
       m = map[string]string{
          "aaa": "111",
          "bbb": "22",
       }
       hasInitMap = true
    }
}

func getValue1(key string) string {
    initMap()
    return m[key]
}

写法2:

// 定义一次执行对象
var once sync.Once

func initMap2() {
    m = map[string]string{
       "aaa": "111",
       "bbb": "22",
    }
}

func getValue2(key string) string {
    // 一次执行
    once.Do(initMap2)
    return m[key]
}

func main() {
    fmt.Println("main ...")
    for i := 0; i < 20; i++ {
       fmt.Println(getValue1("aaa"))
       fmt.Println(getValue2("aaa"))
    }
    fmt.Println("success ...")
}

sync.Map 类型ConcurrentHashMap

是安全的Map

atomic.AddInt64(&intV,1) 对基础类型安全操作方法

多线程给变量递增: intV := 3

1. 直接+1 线程不安全

2. 使用Mutex锁代价太大

3. 使用atomic包的方法最好,类似Java中的Atomic

参考

https://blog.csdn.net/weixin_53623989/article/details/136209823

https://blog.csdn.net/e2788666/article/details/130644433

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

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

相关文章

深度学习入门--python入门2

以前学的全忘了&#xff0c;现在算是才开始学&#xff0c;有错误&#xff0c;恳请指正。 目录 1.4 Python脚本文件 1.4.1保存为文件 1.4.2 类 1.5 Numpy 1.5.1 导入Numpy 1.5.2 生成Numpy数组 1.5.3 Numpy的算术运算 1.5.4 Numpy的N维数组 1.5.5 广播 1.5.6 访问元素…

题海拾贝:【枚举】P2010 [NOIP 2016 普及组] 回文日期

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》 欢迎点赞&#xff0c;关注&#xff01; 1、题…

Mac端homebrew安装配置

拷打了一下午o3-mini-high&#xff0c;不如这位博主的超强帖子&#xff0c;10分钟结束战斗 跟随该文章即可&#xff0c;2025/2/19亲测可行 mac 安装HomeBrew(100%成功)_mac安装homebrew-CSDN博客文章浏览阅读10w次&#xff0c;点赞258次&#xff0c;收藏837次。一直觉得自己写…

Python高级语法之selenium

目录&#xff1a; 1、selenium的使用2、selenium元素定位3、selenium使用功能Phantomjs模拟浏览器启动4、selenium使用功能ChromsHandless模拟浏览器启动 1、selenium的使用 2、selenium元素定位 3、selenium使用功能Phantomjs模拟浏览器启动 4、selenium使用功能ChromsHandles…

2025年3月最新算法-鲸鱼迁徙优化算法Whale Migration Algorithm-附Matlab免费代码

引言 本期介绍了一种基于座头鲸协同迁移行为的创新生物启发式优化方法——鲸鱼迁徙优化算法Whale Migration Algorithm&#xff0c;WMA。该算法于2025年3月最新发表在期刊 Results in Engineering 在本节中&#xff0c;我们概述了开发鲸鱼迁移算法&#xff08;WMA&#xff09;…

flowable适配达梦数据库

文章目录 适配相关问题无法从数据库产品名称“DM DBMS”中推断数据库类型分析解决 构建ibatis SqlSessionFactory时出错&#xff1a;inStream参数为null分析解决 liquibase相关问题问题一&#xff1a;不支持的数据库 Error executing SQL call current_schema: 无法解析的成员访…

Jenkins整合Jmeter实现接口自动化测试

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、安装jmeter 下载&#xff1a;http://jmeter.apache.org/download_jmeter.cgi 这里我用了一台Windows安装jmeter用来写接口测试的脚本&#xff0c;启动前修改j…

高级推理的多样化推理与验证

25年2月来自波士顿大学、NotBadMath.AI、谷歌、哥伦比亚大学、MIT、Intuit公司和斯坦福大学的论文“Diverse Inference and Verification for Advanced Reasoning”。 OpenAI o1、o3 和 DeepSeek R1 等推理 LLM 在数学和编码方面取得重大进展&#xff0c;但仍发现 IMO 组合问题…

清华大学:DeepSeek与AI幻觉(31页PDF)

PDF深入探讨了AI幻觉的概念、原因、评测方法及其实用应用&#xff0c;特别是在金融领域的具体案例。首先介绍了AI幻觉的定义&#xff0c;主要包括数据偏差、泛化困境、知识固化和意图误解四种情况&#xff0c;以及这些因素导致AI产出不合理结果的原因。随后&#xff0c;通过音乐…

AWS云从业者认证题库 AWS Cloud Practitioner(2.21)

题库持续更新&#xff0c;上方二维码查看完整题库&#xff01; 公司希望减少开发人员用于运行代码的物理计算资源,通过启用无服务器架构&#xff0c;哪种服务可以满足该需求? A&#xff1a; Amazon Elastic Compute Cloud (Amazon EC2) B&#xff1a; AWS Lambda C&#xff1a…

网络工程师 (43)IP数据报

前言 IP数据报是互联网传输控制协议&#xff08;Internet Protocol&#xff0c;IP&#xff09;的数据报格式&#xff0c;由首部和数据两部分组成。 一、首部 IP数据报的首部是控制部分&#xff0c;包含了数据报传输和处理所需的各种信息。首部可以分为固定部分和可变部分。 固定…

京准电钟:水利控制系统网络时间同步设计与应用

京准电钟&#xff1a;水利控制系统网络时间同步设计与应用 京准电钟&#xff1a;水利控制系统网络时间同步设计与应用 引言 在水利工程中&#xff0c;控制系统的高效运行依赖于精准的时间同步。水电站、泵站、闸门控制、水文监测等子系统的协同作业需要毫秒甚至微秒级的时间…

QML 实现一个动态的启动界面

QML 实现一个动态的启动界面 一、效果查看二、源码分享三、所用到的资源下载 一、效果查看 二、源码分享 工程结构 main.qml import QtQuick import QtQuick.Controls import QtQuick.Dialogs import Qt.labs.platformWindow {id:windowwidth: 640height: 400visible: truetit…

【论文阅读】SAM-CP:将SAM与组合提示结合起来的多功能分割

导言 近年来&#xff0c;视觉基础模型的快速发展推动了多模态理解的进步&#xff0c;尤其是在图像分割任务中。例如&#xff0c;Segment Anything模型&#xff08;SAM&#xff09;在图像Mask分割上表现出色&#xff0c;但在语义及实例分割方面仍存在局限。本文提出的SAM-CP&am…

逻辑架构与软件架构在PREEvision中的设计关系

1 Introduction 在如今汽车电子系统的开发过程中&#xff0c;系统架构设计是至关重要的环节。无论是汽车控制系统、信息娱乐系统&#xff0c;还是电动驱动系统&#xff0c;架构设计都决定了整个系统的功能、性能以及后期的可维护性和可扩展性。 在往期文章中&#xff0c;我们…

武汉火影数字|VR沉浸式空间制作 VR大空间打造

VR沉浸式空间制作是指通过虚拟现实技术创建一个逼真的三维环境&#xff0c;让用户能够沉浸在这个环境中&#xff0c;彷佛置身于一个全新的世界。 也许你会好奇&#xff0c;VR 沉浸式空间究竟是如何将我们带入那奇妙的虚拟世界的呢&#xff1f;这背后&#xff0c;离不开一系列关…

大数据学习之任务流调度系统Azkaban、Superset可视化系统

一.任务流调度系统Azkaban 1.课程介绍 2.为什么需要工作流调度系统 3.AZKABAN是什么 4.AZKABAN下载 5.制作安装包 6.tar包准备 7.MYSQL配置AZKABAN 8.配置EXECUTOR SERVER 9.配置WEBSERVER 10.单作业实战_yaml语言(今天稍晚更新) 11.单作业实战 12.多作业依赖实战 13.失败自动重…

在VS-qt的程序中,后期增加PCH预编译功能,提高编译速度

由于前期创建qt程序的时候未勾选pch功能,导致没有启动预编译的功能. 这种情况下需要增加pch功能应该怎么做? 在项目中增加2个文件 stdafx.h和stdafx.cpp文件 stdafx.h增加qt常用头文件 #pragma once //windows #include <windows.h>//qt常用 #include <QObject&g…

蓝桥云客 路径之谜

11.路径之谜 - 蓝桥云课 路径之谜 题目描述 小明冒充X星球的骑士&#xff0c;进入了一个奇怪的城堡。 城堡里边什么都没有&#xff0c;只有方形石头铺成的地面。 假设城堡地面是nn个方格。如下图所示。 按习俗&#xff0c;骑士要从西北角走到东南角。可以横向或纵向移动&…

【Python项目】基于Python的语音数据及标注核对审核系统

【Python项目】基于Python的语音数据及标注核对审核系统 技术简介&#xff1a; 采用Python技术、MySQL数据库、Django框架等实现。 系统简介&#xff1a; 语音数据及标注核对审核系统是一个基于B/S架构的语音数据处理平台&#xff0c;旨在通过自动化的方式对语音数据进行标…