Go 语言进阶 - 工程进阶

2023-06-24 22:00:00

前言: \textcolor{Green}{前言:} 前言:

💞这个专栏就专门来记录一下寒假参加的第五期字节跳动训练营
💞从这个专栏里面可以迅速获得Go的知识

今天的内容包括以下两个内容。关于实践的内容我会在后续发布出来。

01.语言进阶:从并发编程的视角了解Go高性能的本质。

02.依赖管理:了解GO语言依赖管理的演进路线

课程代码相关链接

一、语言进阶

1.并发 VS 并行

image.png

区别:并发不是并行。并行是让不同的代码片段同时在不同的物理处理器上执行。并行的关键是同时做很多事情,而并发是指同时管理很多事情,这些事情可能只做了一半就被暂停去做别的事情了。

1.1 Goroutine(协程)

使用者分配足够多的任务,系统能自动帮助使用者把任务分配到 CPU 上,让这些任务尽量并发运作。这种机制在 Go语言中被称为 goroutine。

下图中的协程的栈是 KB 级别。线程是栈 MB 级别

image.png

如果不要求快速那么我们直接 for 循环即可,快速我们就需要开多个协程进行。

go开启协程非常简单,只需要在函数前面加上 go 关键字。

image.png

1.2 CSP(Communicating Sequential Processes)

image.png

一定要记住
DO NOT COMMUNICATE BY SHARING MEMORY; INSTEAD, SHARE MEMORY BY COMMUNICATING.
“不要以共享内存的方式来通信,相反,要通过通信来共享内存。”

1.3 Channel

image.png

无缓冲通道也被称为同步通道
有缓冲通道的后面数字代表是可以同时存在几个。

image.png

1.4 并发安全 Lock

image.png

并发安全问题是有一定概率导致错误的

1.5 WaitGroup

WaitGroup 暴露了三个方法:Add()、 Done()、 Wait();
image.png

和刚开始是多个协程打印例子。这里我们使用 WaitGroup 实现协程的同步阻塞。

image.png

总结

Groutine(协程):通过高效的调度模型实现高并发操作。
Channel(通道):通过通信实现共享内存。(Go中推荐)
Sync相关关键字(Lock、WaitGroup等):实现并发安全操作和协程间的同步。

二、依赖管理

依赖指的是各种开发包,利用已经封装好的、经过验证的开发组件或工具来提升自己的研发效率。

goMod

背景

像单体函数只需要依赖原生的SDK。实际的工程会相对复杂,不可能基于标准库 0~1 编码搭建,更多我们会关注业务逻辑的实现。而其他的一些依赖像涉及框架、日志、driver 以及 collection 等一系列依赖都会通过 SDK 的方式引入,这样我们对依赖包的管理就非常重要了
image.png

2.1 Go 依赖管理演进

Go 的依赖管理经历了以下 3 个阶段。
image.png

2.1.1 GOPATH

GOPATH 是 GO 语言支持的一个环境变量,value 是 go 项目的工作区。

目录结构:

  • src 存放 Go 项目的源码;
  • pkg:存放编译的中间产物,加快编译速度;
  • bin:存放 GO 项目编译生成的二进制文件

image.png

2.1.1 GOPATH - 弊端

image.png

如图所示:同一个 pkg,有2个版本(V1,V2),A->A(),B->B(),而 src 下只有只有一个版本存在,那么 AB 项目无法保证都能构建编译通过。在 GOPATH 管理模式下,如果多个项目依赖同一个库,则依赖该库是同一份代码,所以不同项目不能依赖同一个库的不同版本,这不能满足我们的项目依赖需求,为了解决这个问题,出现了govendor

2.1.2 Go Vendor

image.png

Vendor 是当前项目中的一个目录,其中存放了当前项目依赖的副本。在 Vendor 机制下,如果当前项目存在 Vendor 目录,会优先使用该目录下的依赖,如果依赖不存在,会从 GOPATH中查找。
但 Vendor 无法很好解决依赖包的版本变动问题和一个项目依赖同一个包的不同版本的问题。

2.1.2 Go Vendor - 弊端

image.png

如图中所示,如果项目A依赖 pkg b和c,而 B 和 C 依赖了 D 的不同版本,通过 Vendor 的管理模式我们不能很好的控制对于D的依赖版本,一旦更新项目,有可能带来依赖冲突,导致编译出错。
Vendor 不能很清晰的标识依赖的版本概念。所以出现了go module

2.1.3 Go Module

image.png

Go Modules 是 Go 官方推出的依赖管理系统,解决了之前依赖管理系统存在的像无法依赖同一个库的多个版本等问题。Go Module 从 Go 1.16默认开启;我们一般都读为 go mod(突然发现这个好熟悉,因为我之前遇到过)。

最终通过 go.mod 文件管理依赖包版本;通过 go get/go mod 指令工具管理依赖包。实现终极目标:定义版本规则和管理项目依赖关系。

2.2 依赖管理三要素

image.png

依赖管理之前学习java的时候一定不陌生,我们会想到 maven

但是在 go 中,依赖管理主要是三要素

  1. 配置文件,描述依赖 go.mod
  2. 中心仓库管理依赖库 Proxy
  3. 本地工具 go get/mod

2.3 依赖配置

2.3.1 依赖配置 - go.mod

image.png

模块路径用来标识一个模块,从模块路径可以看出从哪里可以找到该模块,如果是 github 前缀则表示可以从 Github 仓库中找到该模块,依赖包的源代码由 github 托管,如果项目的子包想被单独引用,则需要通过单独的 init go.mod 文件进行管理。

中间的则是依赖的原生库 sdk 版本。

最下面的是单元依赖,每个依赖单元由模块路径+版本来唯一标识。

2.3.2 依赖配置 - version

image.png

gopath 和 govendor 都是源码副本方式依赖,没有版本规则的概念,而 gomod 为了方便管理则定义了版本规则,分为语义化版本和基于 commit 伪版本;其中 语义化版本包括 ${MAJOR}.${MINOR}.${patch},不同的 MAJOR 版本标识不兼容的API,所以即使是同一个库,MAJOR版本不同也会被认为是不同的模块;MINOR 版本通常是新增函数或功能,向后兼容;而 patch 版本一般是修复bug;
而基于commit的版本包括 vx.0.0-yyyymmddhhmmss-abcdefgh1234,基础版本前缀是和语义化版本一样的;时间戳(yyyymmddhhmmss),也就是提交 Commit 的时间,最后是校验码(abcdef),包含12位的哈希前缀;每次提交 commit 后 GO 都会默认生成一个伪版本号。

2.3.3 依赖配置 - indirect

image.png

indirect 后缀标识 go.mod 对应的当前模块,没有直接导入该依赖模块的包,也就是非直接依赖,表示间接依赖。

2.3.4 依赖配置 - incompatible

image.png

主版本 2+ 模块会在模块路径增加 /vN 后缀,这能让 go module 按照不同的模块来处理同一个项目不同主版本的依赖。由于 go module 是1.11实验性,引入这个规则提出之前已经有一些仓库打上了2或者更高版本的tag。为了兼容这部分仓库,对于没有 go.mod 文件并且主版本在 2 或者以上的依赖,会在版本号后面加上 + incompatible后缀。

之前讲语义化版本中,对于同一个库的不同 major 版本,需要不同的pkg目录,用不同的gomod文件管理。例如:V1版本在gomod在主目录下,而对于V2版本,则单独有V2目录,用另一个gomod文件管理依赖路径,来表名不同 major 的不兼容性。对于有些 V2+tag 版本的依赖包并未遵循这一定义规则,就会打上 incompatible 标志。

2.3.4 依赖配置 - 依赖图

image.png

选择最低的兼容版本

2.3.5 依赖分发 - 回源

image.png

go 的依赖分发就是从哪里下载,如果下载的问题

github 是比较常见的代码托管系统平台,而 go modules 系统中定义的依赖,可以对应到多版本代码管理系统中某一项目的特定提交或版本。此时对于gomod中定义的依赖,可以直接从对应仓库中下载指定软件依赖,从而完成依赖分发。

image.png

我们发现,直接使用版本管理仓库下载依赖,存在一些问题。1.无法保证构建确定性:软件作者可以直接在代码平台增加/修改/删除 软件版本,导致下次构建使用另外版本的依赖或找不到依赖版本。无法保证依赖可用性;2.依赖软件作者可以直接代码平台删除软件,导致依赖不可用;3.大幅增加第三方代码托管平台压力。

2.3.5 依赖分发 - Proxy

image.png

go proxy 可以解决上面提出的这些问题。go proxy 是一个服务站点,它会缓冲源站中的软件内容,缓存的软件版本不会改变,并且在源站软件删除之后依然可用,从而实现了供“immutablity”和“available”的依赖分发;使用 go proxy 之后,构建时会直接从 go proxy 站点拉取依赖,

2.3.6 依赖分发 - 变量 GOPROXY

image.png

Go Modules 通过 GOPROXY 环境变量控制如何使用 GO PROXY;

GOPROXY是一个 GO PROXY 站点URL列表,可以使用 direct 表示源站。

对于示例配置,整体的依赖寻址路径,会优先从 proxy1下载依赖,如果 proxy1 不存在,就去 proxy2 寻找,如果 proxy2 中不存在则会回源到源站直接下载依赖,缓存到 proxy 站点中。

2.3.7 工具 - go get

这个是go module 的管理工具下使用的。

image.png

2.3.8 工具 - go mod

image.png

我们要注意,在提交之前执行下 go tidy,减少构建时无效依赖包的拉取。

总结

课程内容是非常切合的,通过前一天的语言基础到今天的语言进阶,了解到了并发和并行的区别,也明白了 Go 中是如何选择进行的。同时依赖管理中也发现了和其他语言类似的地方,当然更多的是不同,发现 go 的依赖配置会有更有趣的地方,对比其他工具便捷。至此我也更加明白学习一门语言不是简单的语法,在此基础上可以优化的内容,同时到这个地步也可以进行下一步网络端的项目进行了。期待接下来的课程学习。

参考链接

Go语言进阶与依赖管理

【后端专场 学习资料一】第五届字节跳动青训营

更多推荐

热门免费api接口:含物流api,短信api,天气api等

热门免费api接口:含物流api,短信api,天气api。。。全国快递物流查询:目前已支持600+快递公司的快递信息查询。自动识别快递公司及单号,服务器毫秒响应,数据及时准确。通知短信:短信通知支持三大运营商以及虚拟运营商。短信验证码:支持三大运营商,支持大容量高并发。语音验证码短信:拨打电话告知用户验证码,实现信息验

【C++】动态内存管理 ③ ( C++ 对象的动态创建和释放 | new 运算符 为类对象 分配内存 | delete 运算符 释放对象内存 )

文章目录一、C++对象的动态创建和释放1、C语言对象的动态创建和释放的方式2、C++语言对象的动态创建和释放的方式二、代码示例-对象的动态创建和释放一、C++对象的动态创建和释放使用C语言中的malloc函数可以为类对象分配内存;使用free函数可以释放上述分配的内存;使用C++语言中的new运算符也可以为类对象分配内

【C++】动态内存管理 ② ( new 运算符 为 基础数据类型 / 基础数据数组类型 分配堆内存 )

文章目录一、C++对象的动态创建和释放二、new运算符为基础数据类型/基础数据数组类型分配堆内存1、语法说明2、语法简单示例3、代码示例-基础类型内存分配4、代码示例-基础数组类型内存分配三、完整代码示例-new运算符为基础数据类型/基础数据数组类型分配堆内存一、C++对象的动态创建和释放动态内存管理在C++语言中,就

浅谈C++|多态篇

1.多态的基本概念多态是C++面向对象三大特性之一多态分为两类1.静态多态:函数重载和运算符重载属于静态多态,复用函数名·2.动态多态:派生类和虚函数实现运行时多态静态多态和动态多态区别:·静态多态的函数地址早绑定–编译阶段确定函数地址·动态多态的函数地址晚绑定–运行阶段确定函数地址下面通过案例进行讲解多态动态多态满足

MySQL之优化SELECT语句

MySQL之优化SELECT语句文章目录MySQL之优化SELECT语句摘要:引言:1.MySQL性能提成优化概述2.WHERE子句优化3.范围优化4.哈希联接优化5.储存引擎下的优化6.索引条件下推优化7.嵌套循环联接算法8.嵌套联接优化(JOIN)总结:摘要:本文主题为MySQL优化SELECT语句,涵盖了数据库性

MySQL什么情况下会死锁,发生了死锁怎么处理呢?

🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年6月CSDN上海赛道top4。🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。🏆本文已收录于PHP专栏:MySQL的100个知识点。🎉欢迎👍点赞✍评论⭐收藏文章目录🚀一、前言-关于数据

数据库 MVCC 详解

目录1.什么是MVCC?2.MVCC的好处?3.快照读?当前读分别是什么?怎么理解?3.1快照读3.2当前读4.MVCC实现原理4.1隐藏字段4.2undolog(版本链)4.3readView5.readView深层详解6.数据库的四种隔离级别7.读已提交和可重复读的区别?7.1MVCC主要作用体现在读已提交和可重复

【Rust 基础篇】Rust 非对象安全

导言在Rust中,Trait是一种用于实现共享行为和抽象的重要特性。然而,并非所有的Trait都是对象安全的。当Trait不满足对象安全的条件时,就被称为非对象安全的Trait。本篇博客将深入探讨Rust中的非对象安全问题,解释什么是非对象安全,为什么会出现这种情况,以及如何处理和避免非对象安全的问题。让我们开始吧!什

「大数据-0」虚拟机VMware安装、配置、使用、创建虚拟机集群教程

目录一、下载VMwareWworkstationPro16二、安装VMwareWworkstationPro16三、检查与设置VMware的网卡1.检查2.设置VMware网段四、在VMware上安装Linux虚拟机五、对安装好的虚拟机进行设置1.打开设置2.设置中文3.修改字体大小4.修改终端字体大小5.关闭虚拟机六

4.1.9-映射应用程序体系结构

映射应用程序体系结构IDWSTG-INFO-10总结为了有效地测试应用程序,并能够就如何解决所识别的任何问题提供有意义的建议,了解实际测试的内容非常重要。此外,确定是否应将特定组件视为超出测试范围可能会有所帮助。现代Web应用程序的复杂性差异很大,从在单个服务器上运行的简单脚本到分布在数十个不同系统、语言和组件的高度复

华为云云耀云服务器L实例评测-基于华为云服务器的测试及简单配置

引言云计算已经成为现代企业和个人的重要组成部分。在云计算市场上,华为云一直以来都以其出色的性能和服务质量而闻名。周末的时候,利用华为云云耀云服务器搭建了一个基于hexo的个人博客,我用的是2核2G的3M带宽的配置,访问起来挺丝滑的,记录一下本次对华为云的一些测试及看法,探讨其性能、可靠性以及适用场景,帮助您更好地了解这

热文推荐