Go究竟是否为空切片分配了底层数组

本文永久链接 – https://tonybai.com/2022/02/15/whether-go-allocate-underlying-array-for-empty-slice

这周在“Go语言第一课”的留言区看到一位同学的这样一个问题:

切片是Go语言中的一个重要的语法元素,也是日常Go开发中使用最为频繁的语法元素。有过Go语言开发经验的童鞋估计大多都知道空切片(empty slice)与nil切片(nil slice)比较的梗,这也是Go面试中的一道高频题。

var sl1 = []int{} // sl1是空切片
var sl2 []int     // sl2是nil切片

要真正理解切片,离不开运行时的切片表示。在我的专栏《Go语言精进之路》一书中都有对切片在运行时表示的细致讲解。

切片在运行时由三个字段构成,reflect包中有切片在类型系统中表示的对应的定义:

// $GOROOT/src/reflect/value.go
type SliceHeader struct {
    Data uintptr
    Len  int
    Cap  int
}

基于这个定义我们来理解空切片和nil切片就容易多了。我们用一段代码来看看这两种切片的差别:

// dumpslice.go
package main

import (
    "fmt"
    "reflect"
    "unsafe"
)

func main() {
    var sl1 = []int{}
    ph1 := (*reflect.SliceHeader)(unsafe.Pointer(&sl1))
    fmt.Printf("empty slice's header is %#v\n", *ph1)
    var sl2 []int
    ph2 := (*reflect.SliceHeader)(unsafe.Pointer(&sl2))
    fmt.Printf("nil slice's header is %#v\n", *ph2)
}

在这段代码中,我们通过unsafe包以及reflect.SliceHeader输出了空切片与nil切片在内存中的表示,即SliceHeader各个字段的值。我们在Go 1.18beta2下运行一下上述代码(使用-gcflags ‘-l -N’可关闭Go编译器的优化):

$go run -gcflags '-l -N' dumpslice.go
empty slice's header is reflect.SliceHeader{Data:0xc000092eb0, Len:0, Cap:0}
nil slice's header is reflect.SliceHeader{Data:0x0, Len:0, Cap:0}

通过输出结果,我们看到nil切片在运行时表示的三个字段值都是0;而空切片的len、cap值为0,但data值不为零

好了,此时我们再回到本文开始处那个童鞋提出的那个问题:空切片到底分没分配底层数组

答案是肯定的:没有分配!那么上述代码中空切片在运行时表示中第一个字段data的值0xc000092eb0从何而来,难道不是底层数组的地址么?

要想回答这个问题,我们需要下沉到汇编层面去看。

Go使用plan9的汇编语法,目前市面上关于这种汇编的资料比较少,比较权威是Go官方的asm资料和Rob Pike编写的A Manual for the Plan 9 assembler。此外IBM工程师的 Dropping down Go functions in assembly language这份资料也十分不错。国内《Go语言高级编程》一书以及曹春辉的plan9 assembly 完全解析讲解的十分全面,值得大家参考。

我们以下面这段最简单的有关空切片的代码为例:

// layout6.go

1 package main
2
3 func main() {
4     var sl = []int{}
5     _ = sl
6 }

生成go源码对应汇编代码的主要方法有:go tool compile -S xxx.go和针对编译后的二进制文件使用go tool objdump -S exe_file。

我们看看这段代码对应的汇编代码,我们使用下面命令将上述go源码转换为汇编代码(Go 1.18beta2 on darwin amd64):

$go tool compile -S -N -l layout6.go > layout6.s // -N -l两个命令行选项用于关闭Go编译器的优化,优化后的代码会掩盖实现细节

(在MacOS上)生成的layout6.s汇编代码如下(汇编代码中的FUNCDATA和PCDATA是Go编译器插入的、给GC使用的指示符,这里将其滤掉了):

"".main STEXT nosplit size=48 args=0x0 locals=0x30 funcid=0x0 align=0x0
    0x0000 00000 (layout6.go:3) TEXT    "".main(SB), NOSPLIT|ABIInternal, $48-0 // 48是main函数的栈帧大小,0表示参数大小
    0x0000 00000 (layout6.go:3) SUBQ    $48, SP
    0x0004 00004 (layout6.go:3) MOVQ    BP, 40(SP)
    0x0009 00009 (layout6.go:3) LEAQ    40(SP), BP
    0x000e 00014 (layout6.go:4) LEAQ    ""..autotmp_2(SP), AX
    0x0012 00018 (layout6.go:4) MOVQ    AX, ""..autotmp_1+8(SP)
    0x0017 00023 (layout6.go:4) TESTB   AL, (AX)
    0x0019 00025 (layout6.go:4) JMP 27
    0x001b 00027 (layout6.go:4) MOVQ    AX, "".sl+16(SP)
    0x0020 00032 (layout6.go:4) MOVUPS  X15, "".sl+24(SP)
    0x0026 00038 (layout6.go:6) MOVQ    40(SP), BP
    0x002b 00043 (layout6.go:6) ADDQ    $48, SP
    0x002f 00047 (layout6.go:6) RET
    0x0000 48 83 ec 30 48 89 6c 24 28 48 8d 6c 24 28 48 8d  H..0H.l$(H.l$(H.
    0x0010 04 24 48 89 44 24 08 84 00 eb 00 48 89 44 24 10  .$H.D$.....H.D$.
    0x0020 44 0f 11 7c 24 18 48 8b 6c 24 28 48 83 c4 30 c3  D..|$.H.l$(H..0.
go.cuinfo.packagename. SDWARFCUINFO dupok size=0
    0x0000 6d 61 69 6e                                      main
""..inittask SNOPTRDATA size=24
    0x0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
    0x0010 00 00 00 00 00 00 00 00                          ........
gclocals·33cdeccccebe80329f1fdbee7f5874cb SRODATA dupok size=8
    0x0000 01 00 00 00 00 00 00 00                          ........
gclocals·ff19ed39bdde8a01a800918ac3ef0ec7 SRODATA dupok size=9
    0x0000 01 00 00 00 04 00 00 00 00                       .........

关于汇编语法的问题,大家可以参考前面提供的参考资料,这里不赘述。我们这里最关注的是对应Go源码第4行Go代码的汇编源码,这里我把这段汇编源码单独提出来放在下面:

    0x000e 00014 (layout6.go:4) LEAQ    ""..autotmp_2(SP), AX
    0x0012 00018 (layout6.go:4) MOVQ    AX, ""..autotmp_1+8(SP)
    0x0017 00023 (layout6.go:4) TESTB   AL, (AX)
    0x0019 00025 (layout6.go:4) JMP 27
    0x001b 00027 (layout6.go:4) MOVQ    AX, "".sl+16(SP)
    0x0020 00032 (layout6.go:4) MOVUPS  X15, "".sl+24(SP)

我们逐行看一下:

  • 00014行:将SP寄存器指向的内存单元(该内存单元被命名为autotmp_2)的地址存入AX寄存器中;
  • 00019行:将AX寄存器中存储的值写入地址为SP+8的内存单元中,这个内存单元被命名为autotmp_1;
  • 00023行:将AL寄存器中的值与AX寄存器指向的内存单元的值做逻辑与操作,设置相关标志位;
  • 00025行:无条件跳转至00027行执行;
  • 00027行:将AX寄存器中存储的值写入sl切片变量运行时表示的第一个字段data中,该字段的地址为SP+16;
  • 00032行:使用intel平台上的SIMD指令集SSE的MOVUPS指令通过X15代表的固定的零寄存器对起始地址为SP+24的连续128bit(16个字节)进行清零。即sl切片变量运行时的len和cap字段被清零。

关于X15寄存器的含义,在Go internal ABI specification中有说明。

我这里用一幅图展示一下上面操作后的main函数栈情况:

我们看到切片sl的指向底层数组的指针data的值实际上是一个栈上的内存单元的地址,Go编译器并没有在堆上额外分配新的内存空间作为切片sl的底层数组。只是上面汇编代码的第00019行、00023行的操作让人很迷,不知道这两部指令操作的意图为何。

我们再来看一个例子,以进一步证实我们上面的结论。这个例子的源码如下:

// layout7.go
1 package main
2
3 func main() {
4     var sl = []int{}
5     sl = append(sl, 1)
6 }

在这个例子中,我们先是声明了一个空切片sl,之后又通过append为sl追加了一个元素。append时,由于sl为空切片,Go势必会为sl新分配底层存储数组,我们通过对比一下第4行和第5行两个操作的异同来确认“空切片并未分配底层数组”的结论。我们同样通过go tool compile -S命令得到该源码对应的汇编代码:

$go tool compile -S -N -l layout7.go > layout7.s

layout7.s中main函数的汇编代码如下(过滤掉了PCDATA和FUNCDATA指示符行):

"".main STEXT size=114 args=0x0 locals=0x70 funcid=0x0 align=0x0
    0x0000 00000 (layout7.go:3) TEXT    "".main(SB), ABIInternal, $112-0
    0x0000 00000 (layout7.go:3) CMPQ    SP, 16(R14)
    0x0004 00004 (layout7.go:3) JLS 107
    0x0006 00006 (layout7.go:3) SUBQ    $112, SP
    0x000a 00010 (layout7.go:3) MOVQ    BP, 104(SP)
    0x000f 00015 (layout7.go:3) LEAQ    104(SP), BP
    0x0014 00020 (layout7.go:4) LEAQ    ""..autotmp_2+64(SP), BX
    0x0019 00025 (layout7.go:4) MOVQ    BX, ""..autotmp_1+72(SP)
    0x001e 00030 (layout7.go:4) TESTB   AL, (BX)
    0x0020 00032 (layout7.go:4) JMP 34
    0x0022 00034 (layout7.go:4) MOVQ    BX, "".sl+80(SP)
    0x0027 00039 (layout7.go:4) MOVUPS  X15, "".sl+88(SP)
    0x002d 00045 (layout7.go:5) JMP 47
    0x002f 00047 (layout7.go:5) LEAQ    type.int(SB), AX
    0x0036 00054 (layout7.go:5) XORL    CX, CX
    0x0038 00056 (layout7.go:5) MOVQ    CX, DI
    0x003b 00059 (layout7.go:5) MOVL    $1, SI
    0x0040 00064 (layout7.go:5) CALL    runtime.growslice(SB)
    0x0045 00069 (layout7.go:5) LEAQ    1(BX), DX
    0x0049 00073 (layout7.go:5) JMP 75
    0x004b 00075 (layout7.go:5) MOVQ    $1, (AX)
    0x0052 00082 (layout7.go:5) MOVQ    AX, "".sl+80(SP)
    0x0057 00087 (layout7.go:5) MOVQ    DX, "".sl+88(SP)
    0x005c 00092 (layout7.go:5) MOVQ    CX, "".sl+96(SP)
    0x0061 00097 (layout7.go:6) MOVQ    104(SP), BP
    0x0066 00102 (layout7.go:6) ADDQ    $112, SP
    0x006a 00106 (layout7.go:6) RET
    0x006b 00107 (layout7.go:6) NOP
    0x006b 00107 (layout7.go:3) CALL    runtime.morestack_noctxt(SB)
    0x0070 00112 (layout7.go:3) JMP 0
    ... ...

有了对layout6.s的汇编的分析的基础,再来看这段汇编似乎就好很多了。首先layout7.s中对应var sl = []int{}代码的第00020到00039的原理与layout6.s一致。sl的data字段被赋值为一个栈上内存单元(SP+64)的地址。

从第00047到00073实际上是为调用runtime.growslice函数做准备以及调用runtime.growslice函数。runtime.growslice函数负责在堆上分配新的底层数组用于存储切片sl的元素。runtime.growslice返回后,我们看到,第00075行,Go将一个立即数1写入AX寄存器指向的内存单元,即growslice新分配的底层数组的第一个元素的内存单元。

之后,sl的三个字段被重新做了赋值:

    0x0052 00082 (layout7.go:5) MOVQ    AX, "".sl+80(SP)
    0x0057 00087 (layout7.go:5) MOVQ    DX, "".sl+88(SP)
    0x005c 00092 (layout7.go:5) MOVQ    CX, "".sl+96(SP)

我们看到:00082行,sl的data字段(SP+80)被赋值为AX寄存器中的值,即堆上分配新的底层数组的地址。而后的len和cap字段也分配用DX和CX寄存器的值做了赋值,这两个寄存器分配存储了切片的len和cap。

我这里同样用一幅示意图展示append后main函数栈的情况:

通过这个例子,我们可以看到,如果Go在堆上为切片分配底层数组,我们会在汇编代码中看到growslice或newobject这样的调用。

如果一个非空切片没有逃逸到堆上,那么Go也可能在栈上为该切片分配底层数组空间,比如下面这段代码:

// layout10.go
package main

func main() {
    var sl = []int{11, 12, 13}
    _ = sl
}

它对应的汇编如下:

"".main STEXT nosplit size=103 args=0x0 locals=0x40 funcid=0x0 align=0x0
    0x0000 00000 (layout10.go:3)    TEXT    "".main(SB), NOSPLIT|ABIInternal, $64-0
    0x0000 00000 (layout10.go:3)    SUBQ    $64, SP
    0x0004 00004 (layout10.go:3)    MOVQ    BP, 56(SP)
    0x0009 00009 (layout10.go:3)    LEAQ    56(SP), BP
    0x000e 00014 (layout10.go:4)    MOVUPS  X15, ""..autotmp_2(SP)
    0x0013 00019 (layout10.go:4)    MOVUPS  X15, ""..autotmp_2+8(SP)
    0x0019 00025 (layout10.go:4)    LEAQ    ""..autotmp_2(SP), AX
    0x001d 00029 (layout10.go:4)    MOVQ    AX, ""..autotmp_1+24(SP)
    0x0022 00034 (layout10.go:4)    TESTB   AL, (AX)
    0x0024 00036 (layout10.go:4)    MOVQ    $11, ""..autotmp_2(SP)
    0x002c 00044 (layout10.go:4)    TESTB   AL, (AX)
    0x002e 00046 (layout10.go:4)    MOVQ    $12, ""..autotmp_2+8(SP)
    0x0037 00055 (layout10.go:4)    TESTB   AL, (AX)
    0x0039 00057 (layout10.go:4)    MOVQ    $13, ""..autotmp_2+16(SP)
    0x0042 00066 (layout10.go:4)    TESTB   AL, (AX)
    0x0044 00068 (layout10.go:4)    JMP 70
    0x0046 00070 (layout10.go:4)    MOVQ    AX, "".sl+32(SP)
    0x004b 00075 (layout10.go:4)    MOVQ    $3, "".sl+40(SP)
    0x0054 00084 (layout10.go:4)    MOVQ    $3, "".sl+48(SP)
    0x005d 00093 (layout10.go:6)    MOVQ    56(SP), BP
    0x0062 00098 (layout10.go:6)    ADDQ    $64, SP
    0x0066 00102 (layout10.go:6)    RET

这段汇编代码就留给大家自己阅读分析吧。


“Gopher部落”知识星球正式转正(从试运营星球变成了正式星球)!“gopher部落”旨在打造一个精品Go学习和进阶社群!高品质首发Go技术文章,“三天”首发阅读权,每年两期Go语言发展现状分析,每天提前1小时阅读到新鲜的Gopher日报,网课、技术专栏、图书内容前瞻,六小时内必答保证等满足你关于Go语言生态的所有需求!部落目前虽小,但持续力很强,欢迎大家加入!

img{512x368}

img{512x368}
img{512x368}
img{512x368}

我爱发短信:企业级短信平台定制开发专家 https://tonybai.com/。smspush : 可部署在企业内部的定制化短信平台,三网覆盖,不惧大并发接入,可定制扩展; 短信内容你来定,不再受约束, 接口丰富,支持长短信,签名可选。2020年4月8日,中国三大电信运营商联合发布《5G消息白皮书》,51短信平台也会全新升级到“51商用消息平台”,全面支持5G RCS消息。

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

Gopher Daily(Gopher每日新闻)归档仓库 – https://github.com/bigwhite/gopherdaily

我的联系方式:

  • 微博:https://weibo.com/bigwhite20xx
  • 微信公众号:iamtonybai
  • 博客:tonybai.com
  • github: https://github.com/bigwhite
  • “Gopher部落”知识星球:https://public.zsxq.com/groups/51284458844544

微信赞赏:
img{512x368}

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

2021年Go语言盘点:厉兵秣马强技能,蓄势待发新征程

本文永久链接 – https://tonybai.com/2022/01/16/the-2021-review-of-go-programming-language

由于日常忙工作,闲时忙专栏,我早已策划的2021年Go语言盘点这篇文章一直拖到了2022年元旦之后才开始落笔。

2021年,Go迈过了其开源的第12个年头。虽然已经演进了10余年,但在编程语言这个领域中,Go依旧属于“小字辈”,仍处于快速的成长演化期。

纵观整个2021年,如果要用一句话来形容Go语言的发展,那就是厉兵秣马,蓄势待发。“厉兵秣马”这个成语的意思是把兵器磨快,把战马喂饱,形容做好战备,也比喻事前做好准备工作。那么2021年的Go究竟在为什么做准备呢?毫无疑问,它就是2022年泛型语法特性的落地。泛型既是Go社区最关注的语法特性,也是Go在语言特性方面的又一个“杀手锏”。

“Go语言第一课”专栏的第一讲“前世今生:你不得不了解的Go的历史和现状”一文中,我曾提到过:绝大多数主流编程语言将在其诞生后的第15至第20年间大步前进。按照这个编程语言的一般规律,已经迈过开源第12个年头的Go很可能将进入自己的黄金5-10年。而2022年很大可能会成为Go语言黄金5-10年的起点,并且其标志只能是Go泛型语法的落地。

当然,Go核心团队以及Go社区所做的工作远不止打磨、优化和实现Go泛型语法这么简单,2021也是Go在其他方面成果丰硕的一年。下面我们就来盘点一下整个2021年Go语言的演化情况和当前状态,最后再对Go的2022年做个简单的展望。

我们先来看看2021年围绕Go语言项目以及Go社区都发生了哪些大事件(按时间先后顺序)!

一. 2021年Go大事件回顾

Go 1.16版本发布

按照一年发布两次大版本的节奏,Go核心团队于2021年2月18日发布了Go 1.16版本。该版本拥有一个重要的意义,那就是Go module构建模式成为了默认构建模式,这也意味着Go module构建模式的引入成功。与此同时,这一版本还支持了苹果的M1芯片(通过darwin/arm64环境变量组合);新增io/fs包,建立Go原生文件系统抽象;新增embed包,作为在二进制文件中嵌入静态资源文件的官方方案;进一步对Go链接器进行现代化改造,新版链接器的性能相比于Go 1.15版本有20%-25%的提升,资源占用则下降5%-15%。编译出的二进制文件大小下降10%以上。

2020年Go用户调查结果发布

2021年3月初,Go官网发布了2020年Go用户调查结果。此次调查共收到近1w份有效调查反馈,报告的亮点如下:

  • Go在工作场所和企业中的使用范围不断扩大,76%的受访者在工作中使用Go,66%的人说Go对他们公司的成功至关重要。
  • 总体满意度很高,92%的受访者对使用Go感到满意。
  • 大多数受访者在不到3个月的时间里感觉到了Go的生产力,81%的受访者感觉Go的生产力非常高。
  • 受访者表示会及时升级到最新的Go版本,76%的受访者在头5个月就升级了。
  • Go module得到了普遍的接纳与采用,满意度达到77%,但受访者也强调了对文档改进的需求。
  • Go继续被大量用于API、CLI、Web、DevOps和数据处理。

Go 1.17版本发布

2021年8月16日,Go 1.17版本在经过两个RC版本之后正式发布Go 1.17版本并没有过多受到Go 1.18版本这个“网红”的影响,Go 1.17默默地加入和优化了着实不少的特性。其中最主要的三个变化是:

Go 1.17不再使用“完整module依赖图”,而是引入了pruned module graph(修剪的module依赖图)。修剪的module依赖图就是在完整module依赖图的基础上将那些“占着茅坑不拉屎”、对构建完全没有“贡献”的间接依赖module修剪后的依赖图。使用修剪后的module依赖图进行构建将有助于避免下载或阅读那些不必要的go.mod文件,这样Go命令可以不去获取那些不相关的依赖关系,从而在日常开发中节省时间。

切换到基于寄存器的调用惯例后,一组有代表性的Go包和程序的基准测试显示,Go程序的运行性能提高了约5%,二进制文件大小典型减少约2%。也就是说你的Go源码使用Go 1.17版本重新编译一下就能获得大约5%的性能提升。

Go开源12岁生日

2009年11月10日,Go语言正式对外发布并开源。2021年11月,距那一历史时刻已经过去12年了。Go核心团队技术负责人Russ Cox在Go官博撰文庆祝Go开源12周年。他简单回顾了这一年来Go核心团队与Go社区为Go的发展做出的卓越贡献,展望了在接下来的Go开源的第13个年头中,Go核心团队的工作重点,包括Go module的持续演进、Go泛型的落地、软件材料清单、Go漏洞数据库等。

Go官网切换

在2021年11月末,Go核心团队正式将Go语言官网从golang.org切换到go.dev。Go团队对官网体验的改善工作已经进行了很长时间了,从2019年go.dev被启用,到将godoc.org切换到pkg.go.dev,再到其他原官网功能逐一切换到go.dev上,Go核心团队在一点点的引导Gopher去使用和适应go.dev这个站点。

为了Go社区建设与Go官网改进,Go团队雇佣专人进行对应。Go核心开发团队专职人员的数量逐年增多。根据Go核心团队工程总监SAMEER AJMANI在之前Go Time的AMA环节中透露的信息,当前Go核心团队的规模已经达到了50余人:

不得不感慨一下:有一个有钱的爹是真好啊!

GopherCon 2021和Go 1.18Beta1发布

由于新冠疫情的影响,这两年的GopherCon大会都以网络直播的形式进行。今年的大会改在了12月初。GopherCon大会向来是既是Go社区的风向标,也是Go核心团队与Go社区互动的一个重要平台。在这次大会上,Go核心团队的两位重量级人物Robert Griesemer和Ian Lance Taylor亲自站台为大家讲解即将到来的Go泛型的相关内容与使用建议。

在GopherCon 2021大会余温未尽的时候,Go核心团队在美国时间12月14日宣布Go 1.18 Beta1发布。Go 1.18 Beta 1是第一个公测版,其主要功能变动包括Go泛型(类型参数)、Go工作区模式支持Fuzzing test等。

Go团队这次少见的通过官博来发布一个beta版本,足以证明Go团队对Go 1.18版本的重视,毕竟Go 1.18是Go自诞生以来最大的一次语法变动,Go团队希望Go社区的gopher们广泛参与公测,在Go 1.18版本发布之前尽可能多地找出版本中存在的bug。

二. Go当前状态

经过一年多的发展与演化,Go语言当前的状态究竟如何呢?我们通过几个角度来看一下。

TIOBE排名上升一位

著名编程语言排名指数TIOBE近期发布了2021年各大主流编程语言最终排名:

从上图可以看到,在2021年,Go从2020年终的第14名上升到第13名,继续保持稳健的发展节奏。并且TIOBE配文中认为,除了Swift和Go之外,尚不会有新的编程语言能迅速进入前3名甚至前5名。这样说明了对Go趋势的看好。

在另外一份基于stackoverflow数据的编程语言排行榜redmonk上(仅2021上半年数据,下半年数据尚未发布),Go保持稳定:

职业教育市场对Go的“追捧”可见一斑,Go“钱途”看好

职业教育市场直接反映了就业市场的需求。今年,国内头部的职业教育,比如:极客时间、慕课网都在Go语言这块发力。慕课网有谢大(astaxie)策划,曹春晖(xargin)主讲的Go高级工程师实战营

极客时间更是上新多门Go语言相关专栏与课程,当然也包含笔者的“Go语言第一课”。在笔者与极客时间郭蕾总编的沟通中,郭总透露了极客时间对Go语言的几个判断:

  • 就目前我们的观察来看,Go语言正在加速向企业渗透,越来越多的企业开始用Go。
  • 就目前我们的观察来看,越来越多的开发者考虑将Go语言作为第二门编程语言。
  • 云原生已经成为趋势,而Go语言是其主要采用的语言。
  • 腾讯、字节跳动、美团、阿里、快手等头部公司正在大力推广Go。

Go在国内的就业市场的情况也是越来越好,在年底的一份程序员薪资报告中,我们看到国内Go程序员的平均薪资排在榜首:

这总体上也能反映出Go在国内就业市场的“钱途”还是不错的。

大厂Go新闻/输出盘点

Gopher们或想学习Go的童鞋都十分关注大厂中Go语言的应用情况。不过大厂中编程语言的应用范围只能通过官方或其雇员在一些渠道发布的消息来确认。下面是2021年大厂Go新闻/输出开源产品的盘点,通过这些内容我们可以大致勾勒出Go在大厂的应用情况。

腾讯

2021年初,腾讯官方发布《腾讯研发大数据报告》,在这份报告中,Go语言成为腾讯公司内部增速最快的语言:

2021年腾讯对外输出的公共资料以及开源的Go项目也充分印证了这一点:

可以说腾讯近些年在Go上面的投入很大,产出也颇丰。

字节跳动

字节跳动是国内大厂中拥抱Go的最积极的公司之一。从字节跳动的公开资料来看:

字节跳动的技术体系以Go语言为主。根据最新的调查统计,公司里有超过55%的服务是采用Go的,排名第二的语言是前端的NodeJS,之后是Python、JAVA、C++,Rust也有一些使用。

长期的Go实践让字节跳动内部积累的丰富的Go产品和经验,2021年字节也开启了对外开源之路,并且一次性放出若干基于Go的微服务框架与中间件产品,包括kitex、netpoll、thriftgo等。这些开源项目统一放在https://github.com/cloudwego下面了。

腾讯和字节是拥抱Go的急先锋,其他大厂、独角兽也有一些Go应用的动作,比如:微软发布了Go语言简明教程、其开源的dapr也有持续的演化,并招聘高级工程师参与Go官方编译器、工具生态开发;阿里的sealer;七牛云发布的Go+等。

国外的uber也是公开数据中使用Go打造服务最多的巨头公司,2021年uber也在其工程博客网站发布了一系列Go实践经验的深度文章,值得大家认真拜读和揣摩。

除了上面大厂积极拥抱Go之外,小公司与初创公司也在积极探索Go的落地。只不过小公司数据不好采集,从圈子里、周边朋友、面试时了解的情况,用Go的小公司/初创公司越来越多了。究其原因还是那句话:Go语言是生产力与性能的最佳结合。这对小公司/初创公司而言就是真(省)金(人)白(省)银(机器)啊。 甚至Go已经渗透到新冠防疫领域,昨天得知河北移动支撑的流调系统的后端服务就是Go实现的。

接下来,我们再来展望一下2022年Go的发展情况会怎样。

三. Go语言2022展望

2022年,Go语言的最大事件就是2月份Go 1.18的发布以及Go泛型的伴随落地。泛型的加入势必会给Go社区带来巨大影响。随之而来的将是位于各个层次的Go包的重写或重构:底层库、中间件、数据结构/算法库、乃至业务层面。这一轮之后,Go社区将诞生有关于Go泛型编码的最佳实践,这些实践也会反过来为Go核心团队提供Go泛型演化与在标准库中应用的素材。

但泛型在提升语言表现力的同时,也会带来Gopher们最不想看到的复杂性,也正因为如此,Go核心团队也一直在努力向社区传达“Go泛型使用的一般准则”,以告知大家哪种场景适合使用泛型来加强代码,哪些场合泛型是不合适的。尽力防止泛型语法被滥用。

当然前面也说过,Go 1.18不仅仅是加入泛型,还有Go工作区模式以及原生支持fuzzing,前者是解决本地module开发与引用的方案,后者则为编写漏洞更少的代码提供了帮助。

有泛型加持的Go语言,“吸粉能力”得到了加强,将进一步得到来自其他语言阵营程序员的青睐。相信在2022年后半段,Gopher数量以及Go语言的受关注度都会有一定的增长。

Go泛型即将上路,也刚刚上路,离“完善”这个目标还有一定距离,就像go module一样,预计经过3-5个版本的打磨与优化,Go泛型才会真正成熟起来,并成为Go语言的又一柄利器。

综上,2021年,Go厉兵秣马,强化自身;2022,伴随着泛型的东风,Go语言将开启自己的新征程。


“Gopher部落”知识星球正式转正(从试运营星球变成了正式星球)!“gopher部落”旨在打造一个精品Go学习和进阶社群!高品质首发Go技术文章,“三天”首发阅读权,每年两期Go语言发展现状分析,每天提前1小时阅读到新鲜的Gopher日报,网课、技术专栏、图书内容前瞻,六小时内必答保证等满足你关于Go语言生态的所有需求!部落目前虽小,但持续力很强,欢迎大家加入!

img{512x368}

img{512x368}
img{512x368}
img{512x368}

我爱发短信:企业级短信平台定制开发专家 https://tonybai.com/。smspush : 可部署在企业内部的定制化短信平台,三网覆盖,不惧大并发接入,可定制扩展; 短信内容你来定,不再受约束, 接口丰富,支持长短信,签名可选。2020年4月8日,中国三大电信运营商联合发布《5G消息白皮书》,51短信平台也会全新升级到“51商用消息平台”,全面支持5G RCS消息。

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

Gopher Daily(Gopher每日新闻)归档仓库 – https://github.com/bigwhite/gopherdaily

我的联系方式:

  • 微博:https://weibo.com/bigwhite20xx
  • 微信公众号:iamtonybai
  • 博客:tonybai.com
  • github: https://github.com/bigwhite
  • “Gopher部落”知识星球:https://public.zsxq.com/groups/51284458844544

微信赞赏:
img{512x368}

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats