Go embed 简明教程

Go编译的程序非常适合部署,如果没有通过CGO引用其它的库的话,我们一般编译出来的可执行二进制文件都是单个的文件,非常适合复制和部署。在实际使用中,除了二进制文件,可能还需要一些配置文件,或者静态文件,比如html模板、静态的图片、CSS、javascript等文件,如何这些文件也能打进到二进制文件中,那就太美妙,我们只需复制、按照单个的可执行文件即可。

一些开源的项目很久以前就开始做这方面的工作,比如gobuffalo/packrmarkbates/pkgerrakyll/statikknadh/stuffbin等等,但是不管怎么说这些都是第三方提供的功能,如果Go官方能内建支持就好了。2019末一个提案被提出issue#35950,期望Go官方编译器支持嵌入静态文件。后来Russ Cox专门写了一个设计文档Go command support for embedded static assets, 并最终实现了它。

Go 1.16中包含了go embed的功能,而且Go1.16基本在一个月左右的时间就会发布了,到时候你可以尝试使用它,如果你等不及了,你也可以下载Go 1.16beta1尝鲜。

本文将通过例子,详细介绍go embed的各个功能。

阅读全文

如何写出内存泄露的程序?

Go语言语法简单,学习起来容易,也容易上手,所以越来越多的公司和个人采用Go语言开发应用程序。不管使用什么语言,内存泄露是经常遇到的一类问题,而使用Go语言编写内存泄露的代码却不容易,本文将教你几招编写出内存泄露的代码,以满足你创造出内存泄露bug的心里需求。

即使你编写出内存泄露的bug,一般来说也很容易通过pprof查找出来,或者通过pprof的两次对比中找出哪一块出现的问题,所以不要因为写出bug就沾沾自喜,此类bug还是很容易被发现的。

阅读全文

go os/exec 简明教程

Go标准库提供了便利的方法,可以很容易地运行外部命令,一般我们会使用os/exec包下的方法实现执行外部命令以及和外部命令交互。os/exec包装了os.StartProcess方法,更方便的进行输入和输出的访问,提供I/O pipe等功能。我会通过两篇文章专门介绍Go启动新进程,执行外部命令的方法,这是第一篇,专门介绍os/exec库。

阅读全文

Go 运行程序中的线程数

稍微入门Go语言的程序员都知道,GOMAXPROCS变量可以限制并发运行用户态Go代码操作系统的最大线程数,你甚至可以通过调用函数func GOMAXPROCS(n int) int在程序运行时改变最大线程数的大小,但是当你进一步阅读文档,或者更深入的应用Go语言开发的时候,你就会发现,实际线程数要比你设置的这个数要大,有时候甚至远远大于你设置的数值,更悲剧的是,即使你的并发任务回退到没有几个的时候,这些线程数还没有降下来,白白浪费内存空间和CPU的调度。

阅读全文

Go运行时中的 Mutex

我在极客时间上开了一门面向中高级Go程序员的课程:Go 并发编程实战课,有读者问Go channel中的实现中使用了mutex,这个mutex和标准库中的Mutex有什么不同?正好在百度厂内分享Go相关课程中有同事也提出了相同的问题,所以我专门写一篇文章介绍一下。

阅读全文

分析Go程序的Off-CPU性能

性能问题可以分为两种类型:

  • On-CPU: 线程花费在CPU上的时间。
  • Off-CPU: 线程阻塞在I/O、锁、计时器、页交换等场景中的等待时间。

Off-CPU性能分析砖窑用来测量和研究off-CPU时间,所以它不同于CPU profiling只检查线程在CPU上的运行时间,而是专门研究阻塞的线程状态,如下图所示:

阅读全文

Go Race Detector报假警?

最近写了一篇使用Go实现高效lock-free队列的文章,主要是根据Maged M. Michael 和 Michael L. Scott 的论文中提到的两个算法,其中一个算法是利用两个lock实现分别控制head、tail实现的队列,算法都超级简单,所以使用Go实现起来也是非常的容易。

最近一位网友提了一个issue,发现使用go race detector很容易就报data race错误。上述论文已经发表了24年了,可以说久经学术界和工程界同仁的考验,但是这位网友也提供了可以重现的测试显示有data race问题,这是怎么回事呢?

阅读全文

使用 Go 实现 lock-free 的队列

队列(queue)是非常常用的一个数据结构,它只允许在表的前端(head)进行出队(dequeue)操作,而在表的后端(tail)进行入队(enqueue)操作。和栈数据结构一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾(tail),进行删除操作的端称为队头(header)。

在并发环境中使用队列,就必须考虑到多线程(多纤程)并发读写的问题,可能存在多个写(入队)操作线程,同时也可能存在多个线程读操作线程,在这种情况下,我们要保证数据的不丢失,不重复,而且也要保证队列的功能不变,也就是先入先出的逻辑,只要存在数据,就可以出列。

诚然,通过一个排外锁可以实现队列的并发访问。一般实现队列的时候通过指针,而且只在队头队尾操作,所以这种排外锁保护的临界区并没有很复杂的执行逻辑,临界区的处理很快,所以一般情况下通过排外锁实现队列的效率已经很高了。但是在一些情况下,通过实现 lock-free 算法,我们可以进一步提升并发队列的性能。

本文介绍 lock-free queue 算法的一些背景知识,并实现了三种并发队列,并提供了性能测试的结果。

代码库可以在github上找到: smallnest/queue

阅读全文

用Go撸一个二叉搜索树

前几天Redis的作者antirez说他朋友面试的时候考到排序问题,然后他说要是他也会考实现一个二叉搜索树,我说在中国某公司,据说面试直接就撸一个红黑树。不是说你技术渣,试问在座的各位有几个现在直接裸写出红黑树?

红黑树太过偏门,但是常用的二叉搜索树你能写出来吗?快排呢?堆排序呢?

阅读全文