跳出Go module的泥潭

说明: go module增在快速的成长中,最近每个版本中(1.11 ~ 1.13)都有很大的变动。 建议你阅读官方的wiki了解go module最新的知识: go/wiki/Modules

最新扩展阅读(go 1.13):Go module 再回顾

Go 1.11 前天已经正式发布了,这个版本包含了两个最重要的feature就是 moduleweb assembly。虽然也有一些简单的教程介绍了go module的特性,但是基本上都是hello world的例子,在实践的过程中, 很多人都在“拼命的挣扎”,包括我自己, 从一些qq群、github的issue, twitter上都可以看到大家茫然或者抱怨的语句。

虽然有三个帮助文件go help modgo help modulesgo help module-get可以了解一些go module的用法,但是感觉Go开发组对module这一特性还是没有很好的做一个全面的介绍,很多情况还得靠大家看源代码或者去猜,比如module下载的文件夹、版本格式的完整声明,module的最佳实践等,并且当前Go 1.11的实现中还有一些bug,给大家在使用的过程中带来了很大的困难。

我也在摸索中前行, 记录了摸索过程中的一些总结,希望能给还在挣扎中的Gopher一些帮助。

Introduction to Go Modules 是一篇很好的go module 入门介绍, 如果你仔细阅读了它,应该就不需要看本文了。

阅读全文

创建最小的Go docker 镜像

虽然曾有一些文章介绍了如何创建一个最小的Go Docker镜像,我也曾写过一篇文章,但是随着Go的新的版本的发布, 以及docker本身的进化,有些技巧已经发生了变化, 本文介绍了最新的创建超小的Go镜像的方法。

阅读全文

[译]Go HttpServer 最佳实践

这是 Cloudflare 的 Filippo Valsorda 2016年发表在Gopher Academy的一篇文章, 虽然过去两年了,但是依然很有意义。

先前 crypto/tls 太慢而net/http也很年轻, 所以对于Go web server来说, 通常我们明智的做法把它放在反向代理的后面, 如nginx等,现在不需要了。

在Cloudflare我们最近试验了直接暴漏纯Go的服务作为主机。 Go 1.8的net/httpcrypto/tls 提供了稳定的、高性能并且灵活的功能。

然后,需要做一些调优的工作,本文我们将展示怎么去调优和使web服务器更稳定。

阅读全文

完全静态编译一个Go程序

在Docker化的今天, 我们经常需要静态编译一个Go程序,以便方便放在Docker容器中。 即使你没有引用其它的第三方包,只是在程序中使用了标准库net,你也会发现你编译后的程序依赖glibc,这时候你需要glibc-static库,并且静态连接。

不同的Go版本下静态编译方式还有点不同,在go 1.10下, 下面的方式会尽可能做到静态编译:

1
CGO_ENABLED=0 go build -a -ldflags '-extldflags "-static"' .

有一个提案请求给编译加一个static,如果接收了的话也许在将来的go中直接使用static

参考文档

  1. http://blog.wrouesnel.com/articles/Totally%20static%20Go%20builds/
  2. https://github.com/golang/go/issues/9344
  3. https://github.com/golang/go/issues/26492

使用 Go 实现快速排序

快速排序(quick sort)号称是二十世纪最伟大的十大算法之一(The Best of the 20th Century: Editors Name Top 10 Algorithms), 但是快速排序也是最不容易实现的排序算法之一 ()。虽然它的原理非常的简单,但实现起来很容易出错。 也曾因为快排导致腥风血雨甚至网站攻击事件。

快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

分治法:将问题分解为若干个规模更小但结构与原问题相似的子问题。递归地解这些子问题,然后将这些子问题的解组合为原问题的解。

利用分治法可将快速排序的分为三步:

  • 在数据集之中,选择一个元素作为”基准”(pivot)。
  • 所有小于”基准”的元素,都移到”基准”的左边;所有大于”基准”的元素,都移到”基准”的右边。这个操作称为分区 (partition) 操作,分区操作结束后,基准元素所处的位置就是最终排序后它的位置。
  • 对”基准”左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。

快速排序平均时间复杂度为O(n log n),最坏情况为O(n2),不稳定排序。

阅读全文

Go Channel 应用模式

Channel是Go中的一种类型,和goroutine一起为Go提供了并发技术, 它在开发中得到了广泛的应用。Go鼓励人们通过Channel在goroutine之间传递数据的引用(就像把数据的owner从一个goroutine传递给另外一个goroutine), Effective Go总结了这么一句话:

Do not communicate by sharing memory; instead, share memory by communicating.

Go内存模型指出了channel作为并发控制的一个特性:

A send on a channel happens before the corresponding receive from that channel completes. (Golang Spec)

除了正常的在goroutine之间安全地传递共享数据, Channel还可以玩出很多的花样(模式), 本文列举了一些channel的应用模式。

促成本文诞生的因素主要包括:

  1. eapache的channels库
  2. concurrency in go 这本书
  3. Francesc Campoy的 justforfun系列中关于merge channel的实现
  4. 我在出版Scala集合手册这本书中对Scala集合的启发

下面就让我们以实例的方式看看这么模式吧。

阅读全文

[译]使用 LLDB 调试 Go 程序

我一般调试Go程序都是通过log日志,性能调试的话通过 pprof 、trace、flamegraph等,主要是Go没有一个很好的集成的debugger,前两年虽然关注了delve,但是在IDE中集成比较粗糙,调试也很慢,所以基本不使用debugger进行调试, 最近看到滴滴的工程师分享的使用debugger在调试Go程序,我觉得有必要在尝试一下这方面的技术了。

本文翻译自 Debugging Go Code with LLDB, 更好的调试Go程序的工具是delve, 因为它是专门为Go开发, 使用起来也很简单,并且还可以远程调试。delve的命令还可参考: dlv cli,但是流行的通用的基础的debugger也是常用的手段之一。我在译文后面也列出了几篇其它关于go debug的相关文章,有兴趣的话也可以扩展阅读一下。

阅读全文

go addressable 详解

Go语言规范中规定了可寻址(addressable)对象的定义,

For an operand x of type T, the address operation &x generates a pointer of type *T to x. The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array. As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal. If the evaluation of x would cause a run-time panic, then the evaluation of &x does too.

对于一个对象x, 如果它的类型为T, 那么&x则会产生一个类型为*T的指针,这个指针指向x, 这是这一段的第一句话,也是我们在开发过程中经常使用的一种获取对象指针的一种方式。

阅读全文