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

这篇具有很好参考价值的文章主要介绍了Go 语言并发编程 及 进阶与依赖管理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

1.0 从并发编程本质了解Go高性能的本质

1.1 Goroutine

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

协程可以理解为轻量级线程

Go更适合高并发场景原因之一:Go语言一次可以创建上万协成

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

“快速”:开多个协成 打印。

go func(): 在函数前加 go 代表 创建协程;

time.Sleep(): 协程阻塞,使主协程 在子协程结束前阻塞不退出

乱序输出 说明并行

1.2 协程通信 CSP (Communicating Sequential Processes)

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

通过通信共享内存:Channel通道遵循 先入先出 保证顺序

1.3Channel

Channel创建需要通过make()函数;

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

无缓冲通道也称 同步通道;有缓冲:缓冲满了之后要拿走才能存

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

通过通信共享内存 例子:

M主函数作为消费者 实际中业务比较复杂,所以会 比 生产者AB慢;我们用 带缓冲的通道 就不会因消费者M的消费速度 影响 生产者的执行效率;

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

1.4 并发安全Lock

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

addWithLock() 通过临界区控制实现;在 每次 x+=1前后加解锁

addWithOutLock() 没加锁; Add 测试函数;对两种实现做5个协程并发执行

结果为:加锁时输出预期结果10000;体现不加锁的并发安全问题

1.5 WaitGroup实现并发任务的同步

计算器=0表示所有并发任务结束

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

1.5.1阻塞的优化

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

好的,以上就是对go并发编程相关概念的介绍,这里简单做个小结

整个章节主要涉及3个方面,一个是协程,通过高效的调度模型实现高并发操作,一个是通道channel.通过通信实现共享内存;最后svnc相关关键字,实现并发安全操作和协程间的同步

2.0 依赖管理

这一章我们主要讲解go的依赖管理, 主要涉及go依赖管理的演进路线和go module实践

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

依赖指各种开发包

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

2.1 Go依赖管理演进

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

2.1.1 GoPATH

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

目录有以下结构:

src: 存放Go项目的源码pkg: 存放编译的中间产物,加快编译速度;

bin: 存放Go项目编译生成的二进制文件

大家想想用gopath依赖管理有 哪些弊端呢?

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

弊端

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

如图,同一个pkg,有2个版本,A-> A0,B-> B0.

而src下只能有1个版本存在,那AB项目无法保证都能编译通过。 也就是在gopath管理模式下,如果多个项目依赖同一个库,则依赖该库是同一份代码,所以不同项目不能依赖同一个库的不同版本,这很显然不能满足我们的项目依赖需求。为了解决这问题,govender出现了

2.1.2 GoVendor

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

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

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

如图项目A依赖pkg b和c,而B和C依赖了D的不同版本,通过vendor的管理模式我们不能很好的控制对于D的依赖版本,一旦更新项目,有可能带来依赖冲突。

归根结底vendor不能清晰的标识依赖的版本概念原因是:他还是依赖源码

下面,go mod就应运而生了。

2.1.3 Go Module

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

Go Modules 是Go语言官方推出的依赖管理系统,解决了之前依赖管理系统存在的诸如无法依赖同一个库的多个版本等问题

G0 module从1.11 开始实验性引入,1.16 默认开启;我们一般都读为go mod,我们也先统一下名称

2.2 依赖管理三要素

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

那其实完善的依赖管理一般都需要3要素,这里我们先整体介绍下

这里熟悉java的同学,可以类比下maven

2.3.1 依赖配置-go.mod

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

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

下面是依赖的原生库sdk版本(go 1.16)

最下面是单元依赖(最关键的部分),每个依赖单元用模块路径(跟上面的对应)+版本来唯一标示

2.3.2 依赖配置-version

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

gopath和govendor都是源码副本方式依赖,没有版本规则概念

而gmod为了方便版本管理 定义了版本规则,分为语义化版本和伪版本

其中语义化版本包括三部分,

不同的MAJOR大版本可以表示是不兼容的

所以即使是同一个库,MAJOR 版本不同也会被认为是不同的模块

MINOR版本通常是新增函数或功能,需要保持在MAJOR下做到前后兼容 patch 版本一般是修复 bug ;

基于commit的伪版本包括3部分,

版本前缀是和语义化版本一样的;

时间戳 yyyymmddhhmmss,也就是提交commit的时间,

最后是校验码(abcdefabcdef,包含 12 位的哈希前缀;每次提交commit后 Go 会默认生成一个伪版本

2.3.3 依赖配置-非直接依赖indirect

下面我们再来看下依赖单元中的特殊标识符,首先是indirect后缀

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

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

2.3.4 依赖配置-incompatible

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

下一个常见是的是incompatible

主版本2+模块(v2以上) 会在模块路径增加/vN(v1,v2这种后缀),这让gomod按照同的模块来处理同一个项目不同主版本的依赖(允许不同MAJOR版本间相互兼容)

由于gomod是1.11实验性引入,所以这项提出之前已经有一些仓库打上了v2或者更高版本的tag了,为了兼容这部分仓库,对于没有go.mod文件并且主版本在2或者以上的依赖,会在版本号后加上+incompatible 后缀

前面讲语义化版本提到,对于同一个库的不同的major版本,需要建立不同的pkg目录,用不同的gomod文件管理

如下面仓库为例,V1版本gomod在主目录下,而对于V2版本,则单独建立了V2目录,用另一个gomod文件管理依赖路径,来表明不同major的不兼容性

那对于有些V2+tag版本的依赖包未遵循这定义规则,就会打上incompatible标志,增加一个compatile的case

依赖图

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

答案竟然是B!

Go底层会根据自己的算法 选择最 低的兼容版本

2.3.5 依赖分发-回源

gomodule的依赖分发,也就是从哪里下载,如何下载的问题

github是比较常见给的代码托管系统平台,而Go Modules 系统中定义的依赖,最终可以对应到多版本代码管理系统中某一项目的特定提交或版本,这样的话,对于go.mod中定义的依赖,则直接可以从对应仓库中下载指定软件依赖,从而完成依赖分发。

但直接使用版本管理仓库下载依赖,存在多个问题

首先无法保证构建确定:软件作者可以直接码平台增加/修改/删除 软件版本,导致下次构建使用另外版本的依赖,或者找不到依赖版本

无法保证依赖可用性:依赖软件作者可以直接代码平台删除软件,导致依赖不可用;大幅增加第三方代码托管平台压力

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

2.3.5 依赖分发-Proxy

而go proxy就是解决这些问题的方案,Go Proxy 是一个服务站点

它会缓存源站中的软件内容,缓存的软件版本不会改变,并且在源站软件删除之后依然可用,从而实现了供“immutability”和“available”的依赖分发;

使用 Go Proxy 之后,构建时会直接从 Go Proxy 站点拉取依赖

类比项目中,如果下游无法满足我们上游的需求、接口,我们可以建一层适配器或Proxy解决

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

2.3.6 依赖分发-变量-GOPROXY

下面讲一下go proxy的使用,Go Modules通过GOPROXY环境变量控制如何使用 Go Proxy;GOPROXY是一个Proxy 站点URL列表,可以使用 “direct”表示源站 用逗号分隔

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

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

2.3.7 工具-go get

对go module的管理工具介绍下使用,首先是go get

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

2.3.8 工具-go mod

go mod,尽量提交之前执行下go tidy,减少构建时无效依赖包的拉取

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin

非常感谢您阅读到这里,如果这篇文章对您有帮助,希望能留下您的点赞👍 关注💖 收藏 💕评论💬感谢支持!!!

Go 语言并发编程 及 进阶与依赖管理,字节跳动后端Go语言,服务器,go,gin文章来源地址https://www.toymoban.com/news/detail-642499.html

到了这里,关于Go 语言并发编程 及 进阶与依赖管理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【GO语言依赖】Go语言依赖管理简述

    在运行环境中,遭遇报错,显示找不到函数 经过研究后发现需要进行依赖管理,进行如下操作后解决: 最早的时候,Go所依赖的所有的第三方库都放在GOPATH这个目录下面。这就导致了同一个库只能保存一个版本的代码。如果不同的项目依赖同一个第三方的库的不同版本,就需

    2024年01月16日
    浏览(45)
  • Go 字节跳动—从需求到上线全流程

    整个课程会带大家先从理论出发,思考为什么有流程 大家以后工作的团队可能不一样,那么不同的团队也会有不同的流程,这背后的逻辑是什么 然后会带大家按照走一遍从需求到上线的全流程,告诉大家在流程的每个阶段,究竟要做什么 最后会给大家介绍一下我们实践当中

    2024年02月07日
    浏览(43)
  • GO语言网络编程(并发编程)并发介绍,Goroutine

    进程和线程 并发和并行 协程和线程 协程:独立的栈空间,共享堆空间,调度由用户自己控制,本质上有点类似于用户级线程,这些用户级线程的调度也是自己实现的。 线程:一个线程上可以跑多个协程,协程是轻量级的线程。 goroutine 只是由官方实现的超级\\\"线程池\\\"。 每个

    2024年02月09日
    浏览(58)
  • GO语言网络编程(并发编程)Channel

    1.1.1 Channel 单纯地将函数并发执行是没有意义的。函数与函数间需要交换数据才能体现并发执行函数的意义。 虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中容易发生竞态问题。为了保证数据交换的正确性,必须使用互斥量对内存进行加锁,这种做法势

    2024年02月09日
    浏览(72)
  • GO语言网络编程(并发编程)select

    1.1.1 select多路复用 在某些场景下我们需要同时从多个通道接收数据。通道在接收数据时,如果没有数据可以接收将会发生阻塞。你也许会写出如下代码使用遍历的方式来实现: 这种方式虽然可以实现从多个通道接收值的需求,但是运行性能会差很多。为了应对这种场景,G

    2024年02月09日
    浏览(89)
  • 【Go】Go语言并发编程:原理、实践与优化

    在当今的计算机世界,多核处理器和并发编程已经成为提高程序执行效率的关键。Go语言作为一门极富创新性的编程语言,凭借其强大的并发能力,在这方面表现出色。本文将深入探讨Go语言并发编程的原理,通过实际代码示例展示其应用,并讨论可能的优化策略。 在了解G

    2024年02月10日
    浏览(58)
  • Go 语言面试题(三):并发编程

    对于无缓冲的 channel,发送方将阻塞该信道,直到接收方从该信道接收到数据为止,而接收方也将阻塞该信道,直到发送方将数据发送到该信道中为止。 对于有缓存的 channel,发送方在没有空插槽(缓冲区使用完)的情况下阻塞,而接收方在信道为空的情况下阻塞。 例如: 协

    2024年02月08日
    浏览(50)
  • Go语言并发编程(千锋教育)

    视频地址:https://www.bilibili.com/video/BV1t541147Bc?p=14 作者B站:https://space.bilibili.com/353694001 源代码:https://github.com/rubyhan1314/go_goroutine 1.1、并发与并行 其实操作系统里对这些概念都有所说明和举例。 并发 并发是指多个任务在同一时间段内交替执行,从外部看似乎是同时执行的。

    2024年02月14日
    浏览(57)
  • GO语言网络编程(并发编程)runtime包

    1.1.1. runtime.Gosched() 让出CPU时间片,重新等待安排任务(大概意思就是本来计划的好好的周末出去烧烤,但是你妈让你去相亲,两种情况第一就是你相亲速度非常快,见面就黄不耽误你继续烧烤,第二种情况就是你相亲速度特别慢,见面就是你侬我侬的,耽误了烧烤,但是还馋就

    2024年02月09日
    浏览(71)
  • 掌握Go语言:Go语言通道,并发编程的利器与应用实例(20)

    通道(Channel)是用来在 Go 程序中传递数据的一种数据结构。它是一种类型安全的、并发安全的、阻塞式的数据传输方式,用于在不同的 Go 协程之间传递消息。 基本概念 创建通道 :使用 make() 函数创建一个通道。 发送数据 :使用 - 操作符向通道发送数据。 接收数据 :使用

    2024年03月21日
    浏览(58)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包