Go语言并发编程及依赖管理

news/2025/1/7 21:36:10/

目录

    • 🧡并发编程
      • Goroutine
      • CSP(Communicating Sequential Processes)
    • 🧡依赖管理
      • 依赖演变
      • 依赖管理三要素

💟这里是CS大白话专场,让枯燥的学习变得有趣!
💟没有对象不要怕,我们new一个出来,每天对ta说不尽情话!
💟好记性不如烂键盘,自己总结不如收藏别人!

🧡并发编程

Goroutine

💌 为什么 Go 语言运行效率如此之高呢?因为它可以充分发挥多核优势,这里有个重要的概念:Goroutine(协程),Go 语言是利用协程达到高并发效果的。

image.png

  • 进程:程序一次动态执行的过程,操作系统资源分配最小单位,有独立内存空间。
  • 线程:轻量级进程,CPU调度的最小单位,多个线程共享所属进程的资源,MB级别。
  • 协程:轻量级线程,由用户控制调度,KB级别。

💌 如何开启一个协程呢?我们只需要在调用的函数前面添加 go 关键字,就能使这个函数以协程的方式运行。

package mainimport ("fmt""time"
)func hello(i int) {println("hello goroutine:" + fmt.Sprint(i))
}func main() {for i := 0; i < 5; i++ {go hello(i) // go + 调用函数名(参数)}time.Sleep(time.Second) // 阻塞,保证子协程执行完之前主线程不退出
}

可以看到打印结果是并发乱序输出的:

image.png

CSP(Communicating Sequential Processes)

💌 Go 语言中协程之间的通信提倡通过通信共享内存,而非通过共享内存实现通信,二者都支持实现,但是听起来很容易混淆,通过画图可以直观演示:

image.png

🍠 通过通信共享内存:通过通道给目标协程发送信息。Channel(通道)分为无缓冲通道和有缓冲通道,构造方式:

  • 无缓冲通道:make(chan int)
  • 有缓冲通道:make(chan int,2)

image.png

如下代码所示,构造生产者A和消费者B可以实现有缓冲通道的协程通信,生产者产生数字,消费者计算数字的平方,并顺序打印。

package mainfunc CalSquare() {src := make(chan int)     // 生产者dest := make(chan int, 3) // 消费者,带缓冲区go func() {               // A协程发送0~9至src中defer close(src) // defer表示延迟到函数结束时执行,用于释放已分配的资源for i := 0; i < 10; i++ {src <- i}}()go func() { // B协程计算src中数据的平方,并发送至dest中defer close(dest)for i := range src {dest <- i * i}}()for i := range dest {println(i)}
}func main() {CalSquare()
}

🍠 通过共享内存通信:需要通过 sync 包中的 lock 进行加锁,如果不加锁会出现问题。如下代码开启5个协程,每个协程进行2000次+1操作,正确结果应该是10000,不加锁的结果不准确。项目中应避免对共享内存进行非并发安全的读写操作。

package mainimport ("sync""time"
)var (x    int64lock sync.Mutex
)func addWithLock() {for i := 0; i < 2000; i++ {lock.Lock() // 加锁x += 1lock.Unlock() // 解锁}
}func addWithoutLock() { // 不使用锁for i := 0; i < 2000; i++ {x += 1}
}func Add() {x = 0for i := 0; i < 5; i++ {go addWithoutLock()}time.Sleep(time.Second)println("WithoutLock x =", x)x = 0for i := 0; i < 5; i++ {go addWithLock()}time.Sleep(time.Second)println("WithLock x =", x)
}func main() {Add()
}

image.png

💌 sync 包中的 WaitGruop 也可以实现并发任务同步,Add(delta int) 开启 delta 个协程,Done() 结束协程,Wait() 阻塞主线程。

image.png

🧡依赖管理

依赖演变

💌 Go 依赖主要经历了 GOPATH -> Go Vendor -> Go Module 演变,现在主要采用 Go Module 方式。不同环境(项目)依赖的版本不同,需要控制依赖库的版本。

  • GOPATH:环境变量,Go 语言的工作区,通过 go get 下载最新版本的包到 src 目录下,项目代码直接依赖 src 下的所有源代码。但是有一个弊端就是无法实现package的多版本控制,A、B 项目可能依赖同一个包的不同版本。
  • Go Vendor:在项目目录下新增 vendor 文件夹,所有依赖包副本形式放在其中,通过 vendor => GOPATH 的方式寻址。但是还有问题就是更新项目时可能出现依赖冲突,依然无法控制依赖的版本。
  • Go Module:通过 go.mod 文件管理依赖包版本,通过 go get/go mod 指令工具管理依赖包。既能定义版本规则,又能管理项目依赖关系。

依赖管理三要素

🍠 配置依赖 go.mode

module example/project/app //依赖管理基本单元go 1.16  //原生库版本require (  //单元依赖标识语法:[Module Path][Version/Pseudo-version]example/lib1 v1.0.2example/lib2 v1.0.0 // indirectexample/lib3 v0.1.0-20190725025543-5a5fe074e612example/lib4 v0.0.0-20180306012644-bacd9c7ef1dd // indirectexample/lib5/v3 v3.0.2  // 主版本2+的模块会在路径后增加/vN后缀example/lib6 v3.2.0+incompatible  // 对于没有go.mod文件且主版本2+的依赖+incompatible
)

go.mode 定义了自己的版本规则,分为语义版本和基于commit伪版本。

  • 语义版本:${MAJOR}.${MINOR}.${PATCH}

    v版本.新增功能.修复bug,不同版本不兼容,功能向下兼容。

  • 基于commit伪版本:${vx.0.0-yyyymmddhhmmss-abcdefgh1234}

    v版本-时间戳-校验码。

🍠 中心仓库管理依赖库 Proxy

对于 go.mod 中定义的依赖,可以从对应仓库(Github)中下载指定软件依赖,从而完成依赖分发,但是会产生如下问题:

  • 无法保证构建确定性:软件作者直接修改软件版本,导致下次构建使用其他版本的依赖,或者找不到依赖版本。
  • 无法保证依赖可用性:软件作者删除软件,导致依赖不可用。
  • 增加第三方压力:代码托管平台负载过大。

可以使用 Go Proxy 解决上述问题,它会缓存源站中的软件内容,缓存的软件版本不会改变,并且在源站软件删除之后依然可用,构建时会直接从 Go Proxy 站点拉取依赖。Go Modules通过 GOPROXY 环境变量控制依赖寻址顺序:如 proxy1 -> proxy2 -> 源站

GOPROXY="https://proxy1.cn, https://proxy2.cn,direct"

🍠 本地工具 go get/mod

image.png
image.png


http://www.ppmy.cn/news/12697.html

相关文章

Http客户端 Feign 的使用 (黑马springcloud笔记)

Feign基本使用 目录Feign基本使用一、Feign代替RestTemplate二、自定义配置三、Feign使用优化1. 底层优化2. 日志优化四、最佳实践方式一&#xff1a;继承方式二&#xff1a;抽取一、Feign代替RestTemplate 步骤&#xff1a; 引入依赖 <dependency><groupId>org.s…

RT-Thread系列--组件初始化

一、目的RT-Thread里面有个特别有意思的软件设计叫做组件自动初始化。有些小伙伴可能是第一次听说&#xff0c;所以这边我解释一下&#xff0c;请看下面的代码片段static void clock_init() {// 时钟初始化 } static void uart_init() {// 串口初始化 } static void i2c_init()…

自动驾驶专题介绍 ———— 超声波雷达

文章目录介绍工作原理特点常见参数介绍 在汽车碰撞事故中&#xff0c;有大约15%的事故是因为倒车时汽车的后视能力不足引起的&#xff0c;因为增加汽车的后视能力的超声波雷达的研究成为了当下的热点之一。安全避免碰撞的前提是快速准确的测量障碍物于汽车之间的距离。超声波雷…

Opencv图像及视频基本操作

✨ 原创不易,还希望各位大佬支持一下 \textcolor{blue}{原创不易,还希望各位大佬支持一下} 原创不易,还希望各位大佬支持一下 👍 点赞,你的认可是我创作的动力! \textcolor{green}{点赞,你的认可是我创作的动力!} 点赞,你的认可是我创作的动力!

Https为什么比Http安全?

Https是在Http之上做了一层加密和认证&#xff1b; 主要的区别是Https在TLS层对常规的Http请求和响应进行加密&#xff0c;同时对这些请求和响应进行数字签名。 Http请求的样式&#xff1a; 明文传输&#xff0c;通过抓包工具可以抓到 GET /hello.txt HTTP/1.1 User-Agent: c…

【JavaEE初阶】第二节.进程篇

文章目录 前言 一、操作系统 二、进程 2.1 进程的概念 2.2 进程的管理​​​​​​​​​​​​​​ 2.3 PCB 2.3.1 PCB里面的一些属性 2.3.2 进程的调度 2.3.3 进程的虚拟地址空间 2.3.4 进程间通信 总结 前言 本节内容我们继续对JavaEE的有关内容进行学习&#xff0c;…

[JavaEE]阻塞队列

专栏简介: JavaEE从入门到进阶 题目来源: leetcode,牛客,剑指offer. 创作目标: 记录学习JavaEE学习历程 希望在提升自己的同时,帮助他人,,与大家一起共同进步,互相成长. 学历代表过去,能力代表现在,学习能力代表未来! 目录: 1.阻塞队列的概念 2.标准库中的阻塞队列 3.生产者…

nacos在国产银河麒麟系统飞腾CPU部署安装

1 jdk安装 1.1 首先查看系统是否自带jdk java -version1.2 卸载系统自带的openjdk apt-get remove openjdk*或者先查看安装的java&#xff1a;dpkg -l | grep java&#xff0c;再根据对应java的package卸载java&#xff1a;sudo apt-get remove ca-certificates-java1.3 安装…