Go 语言进阶 - 工程进阶

news2025/1/9 1:05:56

前言: \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语言进阶与依赖管理

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

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

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

相关文章

新零售破局丨2023年探索全新电商运维模式——永倍达模式深度解析

新零售破局丨2023年探索全新电商运维模式——永倍达模式深度解析 大家好!我是微三云胡佳东,一家专业的电商软件开发公司的负责人。 近年来,随着电商的高速发展,不少电商平台成为了市场经济的优质榜样,互联网市场竞争也…

设计模型学习-UML图

1,简介 UML图有很多种类型,但掌握其中的类图、用例图和时序图就可以完成大部分的工作。其中最重要的便是「类图」,它是面向对象建模中最常用和最重要的图,是定义其他图的基础。 类图主要是用来显示系统中的类、接口以及它们之间的…

Ubuntu环境下读取罗技G29方向盘信息

本篇博客最早发布于实验室公共博客,但已无人维护,现迁移至个人博客 引言 实验室有这么酷的驾驶设备,来了一年还没有实际操作过,早就蠢蠢欲试了,哈哈哈不过之前负责的师兄还在就一直没敢用,现在他毕业了就可…

rust abc(2): 从 hello world 到整数、浮点类型

文章目录 1. 目的2. 搞懂 hello world2.1 代码2.2 fn 的含义2.3 main() 的含义2.4 println! 的含义2.5 行尾分号是必要的吗?2.6 左花括号可以放下一行吗? 3. 数据类型的例子3.1 代码3.2 rust 的注释3.3 编译运行结果3.4 基本数据类型 4. 整数类型的例子4…

SpringMVC系列-3 拦截器

背景 本文作为 SpringMVC系列 的第三篇,以SpringMVC系列-2 HTTP请求调用链为基础,介绍Spring MVC的拦截器。 1.拦截器 SpringMVC的核心实现是DispatcherServlet,本质是一个Servlet实现类,拦截器位于DispatcherServlet逻辑中&am…

MySQL进阶SQL语句2之表连接

目录 1.连接查询 1.1inner(内连接) 1.2left join(左连接) 1.3right join(右连接) 1.4直接查询两个表相同的字段值的数据 2. VIEW(视图) 2.1create view(创建视图…

设计模式之迭代器模式笔记

设计模式之迭代器模式笔记 说明Iterator(迭代器)目录迭代器模式示例类图学生类抽象迭代器角色接口具体迭代器角色类抽象聚合角色接口具体聚合角色类测试类 说明 记录下学习设计模式-迭代器模式的写法。JDK使用版本为1.8版本。 Iterator(迭代器) 意图:提供一种方法顺序访问一…

Python2、3下载安装、环境配置和Python2、3版本共存配置

一、python 版本简介 python 包括 python2、python3 两个大版本,其中 python3 改进了 python2 的一些不足,但由于以前很多应用是用 python2 开发的,维护这些应用还需用到 python2,故 python2 尚未被完全淘汰。 北京时间 2020 年 4…

近期参与开源的心得体会

引言 最近随着Kepler项目加入CNCF sandbox,写一篇blog来记录下参与这个项目半年的发展的心得体会。 运营 项目的运营最好还是专注于项目自身的发展,围绕项目的特点,创新点入手,为大家提供价值,从而自然而然的扩大自…

【计算机网络】计算机网络期末自测题(一)答案

2019-2020 学年第 2 学期自测题答案及评分标准 (卷 1) 计算机网络 一、 填空题: 参考答案: 1 、 01000101 、11100111 3 、 100Mbps、双绞线、基带、全双工 [10Mbps 要求单位] 4 、 报文 5 、 ICMP 6 、 虚电路 7 、 距离矢量、链路状态 …

什么是网络安全?

文章目录 一、概述1.1 网络安全的指标1.2 网络安全的特征 二、网络安全威胁2.1 黑客能破坏的2.2 Internet安全手段2.2.1 端口扫描2.2.2 分组嗅探sniffing2.2.3 IP欺骗Spoofing 2.3 Internet安全威胁2.3.1 DOS拒绝服务 三、密码学3.1 对称加密算法3.1.1 传统加密3.1.2 现代加密技…

Redis(七):Redis基础入门

Redis基础入门 Redis用途Redis优缺点docker运行RedisRedis常用命令String命令Hash命令List命令Set命令ZSet命令全局命令 Redis事务Redis持久化机制RDBAOFRDBAOF(默认) Redis内存淘汰机制Redis对过期Key的处理 Redis用途 Redis是一种开源的NoSQL内存数据库…

【MySql】多版本并发控制MVCC前置知识——隐藏字段、undo日志与Read View

文章目录 3个记录隐藏列字段undo日志模拟 MVCCRead View 数据库并发的场景有三种: 读-读 :不存在任何问题,也不需要并发控制 读-写 :有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读,幻读…

UOS系统下搭建qtcreator编译环境

文章目录 前言一、依赖包说明二、No valid kits found 问题现象三、No valid kits found 问题解决1.查找qt安装路径2.设置Qt Versions3.构建套件(kit)下选择Qt版本4.重新添加工程 前言 本文记录了在UOS系统下如何安装qtcreator以及涉及的依赖包安装&…

冷静期or跌落神坛:净水市场纠结,“易开得”们路在何方?

文丨琥珀消研社 作者丨余二 1986年11月1日,一场火灾拉开了世界三大水污染——莱茵河水污染的序幕。 是夜,位于瑞士巴塞尔市的桑多兹化学公司的一个化学品仓库发生火灾,装有约1250吨剧毒农药的钢罐爆炸,大火持续了4个多小时&…

SpringBoot 线上服务假死,CPU 内存正常,什么情况?

背景 开发小伙伴都知道线上服务挂掉,基本都是因为cpu或者内存不足,出现GC频繁OOM之类的情况。本篇文章区别以上的情况给小伙伴们带来不一样的服务挂掉。 还记得哔哩哔哩713事故中那场诡计多端的0吗? 图片 对就是这个0,和本次事…

团体程序设计天梯赛-练习集L2篇③

🚀欢迎来到本文🚀 🍉个人简介:Hello大家好呀,我是陈童学,一个与你一样正在慢慢前行的普通人。 🏀个人主页:陈童学哦CSDN 💡所属专栏:PTA 🎁希望各…

【golang中的变量 全局/局部/4中声明】

目录 变量变量的分析1.变量的创建的四种形式1.1总结1.2第一种 var a int 声明1.3 第二种 var a string "XXXX" 初始化1.4第三种 var a "XXXX"1.5第四种 a : XXXX 2.一次性声明多个变量3.一次初始化多个变量3.1交换值 4.全局变量--局部变量5. 声明和初始化…

Kafka生产调优源码

一、Kafka硬件配置选择 1.1 场景说明 100 万日活,每人每天 100 条日志,每天总共的日志条数是 100 万 * 100 条 1 亿条。 1 亿/24 小时/60 分/60 秒 1150 条/每秒钟。 每条日志大小:0.5k - 2k(取 1k)。 1150 条/…

算法------排序算法------冒泡排序法

介绍 冒泡排序法又称交换排序法,原理是从第一个元素开始,比较相邻元素的大小,如大小顺序有误,则对调后再进行下一个元素的比较,一次扫描之后可以确保最后一个元素位于正确的位置。接下来进行的第二次扫描,…