大家好,我是煎鱼。 前段时间有播放一条快讯,就是 Go1.17 会正式支持切片(Slice)转换到数据(Array),不再需要用以前那种骚办法了,安全了许多。 但是也有同学提出了新的疑惑,在 Go 语言中,数组其实是用的相对较少的,甚至会有同学认为在 Go 里可以把数组给去掉。 数组相较切片到底有什么优势,我们又应该在什么场景下使用呢? 这是一个我们需要深究的问题,因此今天就跟大家一起来一探究竟,本文会先简单介绍数组和切片是什么,再进一步对数组的使用场景剖析。 一起愉快地开始吸鱼之路。 数组是什么 Go 语言中有一种基本数据类型,叫数组。其格式为:[n]T。是一个包含 N 个类型 T 的值的数组。 基本声明格式为: var a [10]int 代表的是声明了一个变量 a 是一个包含 10 个整数的数组。数组的长度是其类型的一部分,所以数组不能被随意调整大小。 在使用例子上: func main() { var a [2]string a[0] = "脑子进" a[1] = "煎鱼了" fmt.
大家好,我是煎鱼。 前段时间 Go 语言社区有一件事情引爆了热议,那就是 golang-standards/project-layout 项目的 “Go 项目的标准布局” 之争。 没想到,五一假期,认真一看,这个 issues 已经提出将近一个月了,仍然在热议阶段,我想,咱们需要好好的聊聊这个话题。 煎鱼带你了解下的前因后果,再分享我的看法和业务真实情况。 背景 问题发生地 在 GitHub 上有一个项目 Spaghetti(github.com/adonovan/spaghetti),是 Go 软件包的一个依赖性分析工具。 该项目的目录结构如下: 看上去并不复杂,代码量不多,文件平铺也不超过一屏,就是一个布局比较简单的项目。 有一位老哥提出了一个 PR,明确的期望该项目按照 golang-standards/project-layout 项目给出的 “标准” 布局来调整。: 我猜测该项目可能是因为把 Go、HTML、JS、PNG 和 go.
大家好,我是煎鱼。 最近又有同学问我这个日经话题,想转他文章时,结果发现我的公众号竟然没有发过,因此今天我再唠叨两句,好让大家避开这个 “坑”。 有的小伙伴没留意过 Go map 输出、遍历顺序,以为它是稳定的有序的,会在业务程序中直接依赖这个结果集顺序,结果栽了个大跟头,吃了线上 BUG。 有的小伙伴知道是无序的,但却不知道为什么,有的却理解错误? 今天通过本文,我们将揭开 for range map 输出的 “神秘” 面纱,看看它内部实现到底是怎么样的,顺序到底是怎么样? 开始吸鱼之路。 前言 例子如下: func main() { m := make(map[int32]string) m[0] = "EDDYCJY1" m[1] = "EDDYCJY2" m[2] = "EDDYCJY3" m[3] = "EDDYCJY4" m[4] = "EDDYCJY5" for k, v := range m { log.
大家好,我是煎鱼。 前段时间正在疯狂写代码的时候,突然有一个读者给我提了一个问题,让我有了一定的兴趣: 我还是比较感兴趣的,因为是生产环境、有代码,且整组人都懵逼的问题。 在征求了小伙伴的意见后,今天分享出来,大家也思考一下原因,一起规避这个 “坑”。 案例一 代码示例如下: type MyErr struct { Msg string } func main() { var e error e = GetErr() log.Println(e == nil) } func GetErr() *MyErr { return nil } func (m *MyErr) Error() string { return "脑子进煎鱼了" } 请思考一下,这段程序的输出结果是什么?
大家好,我是煎鱼。 前几天我们有聊到《单核 CPU,开两个 Goroutine,其中一个死循环,会怎么样?》的问题,我们在一个细节部分有提到: 有新的小伙伴会产生更多的疑问,那就是在 Go 语言中,是如何抢占 P 的呢,这里面是怎么做的? 今天这篇文章我们就来解密抢占 P。 调度器的发展史 在 Go 语言中,Goroutine 早期是没有设计成抢占式的,早期 Goroutine 只有读写、主动让出、锁等操作时才会触发调度切换。 这样有一个严重的问题,就是垃圾回收器进行 STW 时,如果有一个 Goroutine 一直都在阻塞调用,垃圾回收器就会一直等待他,不知道等到什么时候… 这种情况下就需要抢占式调度来解决问题。如果一个 Goroutine 运行时间过久,就需要进行抢占来解决。 这块 Go 语言在 Go1.2 起开始实现抢占式调度器,不断完善直至今日:
大家好,我是煎鱼。 前段时间我分享了 《手撕 Go 面试官:Go 结构体是否可以比较,为什么?》的文章,把基本 Go struct 的比较依据研究了一番。这不,最近有一位读者,遇到了一个关于 struct 的新问题,不得解。 大家一起来看看,建议大家在看到代码例子后先思考一下答案,再往下看。 独立思考很重要。 疑惑的例子 其给出的例子一如下: type People struct {} func main() { a := &People{} b := &People{} fmt.Println(a == b) } 你认为输出结果是什么呢?
大家好,我是煎鱼。 自古应用程序均从 Hello World 开始,你我所写的 Go 语言亦然: import "fmt" func main() { fmt.Println("hello world.") } 这段程序的输出结果为 hello world.,就是这么的简单又直接。但这时候又不禁思考了起来,这个 hello world. 是怎么输出来,经历了什么过程。 真是非常的好奇,今天我们就一起来探一探 Go 程序的启动流程。 其中涉及到 Go Runtime 的调度器启动,g0,m0 又是什么? 车门焊死,正式开始吸鱼之路。
大家好,我是煎鱼。 前几天分享 Go 群友提问的文章时,有读者在朋友圈下提到,希望我能够针对 Goroutine 泄露这块进行讲解,他在面试的时候经常被问到。 今天的男主角,就是 Go 语言的著名品牌标识 Goroutine,一个随随便便就能开几十万个快车进车道的大杀器。 for { go func() {}() } 本文会聚焦于 Goroutine 泄露的 N 种方法,进行详解和说明。 为什么要问 面试官为啥会问 Goroutine(协程)泄露这种奇特的问题呢? 可以猜测是: Goroutine 实在是使用门槛实在是太低了,随手就一个就能起,出现了不少滥用的情况。例如:并发 map。 Goroutine 本身在 Go 语言的标准库、复合类型、底层源码中应用广泛。例如:HTTP Server 对每一个请求的处理就是一个协程去运行。 很多 Go 工程在线上出事故时,基本 Goroutine 的关联,大家都会作为救火队长,风风火火的跑去看指标、看日志,通过 PProf 采集 Goroutine 运行情况等。
大家好,我是煎鱼。 前几天在分享《Go 结构体是否可以比较,为什么?》时,有小伙伴提出了新的问题: 虽然大家提问题的速度已经超出了本鱼写文章的速度…不过作为宠粉狂鱼,在此刻清明假期时还是写下了这篇文章。 我在网上冲浪时搜索了相关问题,发现 6 年前就有 Go 开发者有一模一样的疑问,真是困扰了一代又一代的小伙伴。 本期的男主角是《Go 结构体和结构体指针调用有什么区别》,希望对大家有所帮助,带来一些思考。 请在此处默念自己心目中的答案,再和煎鱼一同研讨一波 Go 的技术哲学。 结构体是什么 在 Go 语言中有个基本类型,开发者们称之为结构体(struct)。是 Go 语言中非常常用的,基本定义: type struct_variable_type struct { member definition member definition ... member definition } 简单示例:
大家好,我是煎鱼。 最近金三银四,是面试的季节。在我的 Go 读者交流群里出现了许多小伙伴在讨论自己面试过程中所遇到的一些 Go 面试题。 今天的男主角,是与 Go 工程师有调度相关的知识,那就是 “单核 CPU,开两个 Goroutine,其中一个死循环,会怎么样?” 请在此处默念自己心目中的答案,再往和煎鱼一起研讨一波 Go 的技术哲学。 问题定义 针对这个问题,我们需要把问题剖开来看看,其具有以下几个元素: 运行 Go 程序的计算机只有一个单核 CPU。 两个 Goroutine 在运行。 一个 Goroutine 死循环。 根据这道题的题意,可大致理解其想要问的是 Go 调度相关的一些知识理解。