为什么会有atomic.LoadInt32

前些天我们聊了 Golang 内存对齐的话题,后来我突然想到另一个问题:为什么会有 atomic.LoadInt32?可能你觉得思维太跳跃了,容我慢慢道来:首先,有 atomic.LoadInt64 很正常,因为对一个 int64 来说,它的大小是 8 个字节,如果是 32 位平台的话(字长 4 字节),CPU 一次最多操作 4 个字节,需要两次才能拿到全部数据,所以封装一个 atomic.LoadInt64 来实现原子操作;但是,对一个 int32 数据来说,它的大小是 4 字节,不管是 32 位平台(字长 4 字节),还是 64 位平台(字长 8 字节),CPU 应该都可以保证一次操作拿到数据,换句话说,如果读取一个 int32 数据,那么本身就应该是原子的,可是为什么会有 atomic.LoadInt32,这不是脱了裤子放屁么?

继续阅读

浅谈Golang内存对齐

如果你在 golang spec 里以「alignment」为关键字搜索的话,那么会发现与此相关的内容并不多,只是在结尾介绍 unsafe 包的时候提了一下,不过别忘了字儿越少事儿越大:

Computer architectures may require memory addresses to be aligned; that is, for addresses of a variable to be a multiple of a factor, the variable’s type’s alignment. The function Alignof takes an expression denoting a variable of any type and returns the alignment of the (type of the) variable in bytes. For a variable x:

uintptr(unsafe.Pointer(&x)) % unsafe.Alignof(x) == 0

The following minimal alignment properties are guaranteed:

  • For a variable x of any type: unsafe.Alignof(x) is at least 1.
  • For a variable x of struct type: unsafe.Alignof(x) is the largest of all the values unsafe.Alignof(x.f) for each field f of x, but at least 1.
  • For a variable x of array type: unsafe.Alignof(x) is the same as the alignment of a variable of the array’s element type.

当然,如果你以前没有接触过内存对齐的话,那么对你来说上面的内容可能过于言简意赅,在继续学习之前我建议你阅读以下资料,有助于消化理解:

继续阅读

手把手教你用TARS

在中国,有一个简单的方法可以用来判断一个互联网公司够不够大,那就是看其是否开源过 rpc 框架!比如阿里巴巴的 dubbo,或者腾讯的 tars,小公司往往会对这些大公司的产品趋之若鹜,不过一个可悲的现实是大公司自己往往并不用他们开源的版本,这就好比皇帝总是把自己看不上眼的女人赏赐给臣民,不过能得到皇帝的赏赐总是好事,下面让我手把手教你用 tars,更具体的说是 tarsgo,也就是 tars 的 golang 实现。

继续阅读

实战CGO

某项目要集成 PDF 文件的 OCR 功能,不过由于此功能技术难度太大,网络上找不到靠谱的开源实现,最终不得不选择 ABBYY FineReader Engine 的付费服务。可惜 ABBYY 只提供了 C++ 和 Java 两种编程语言的 SDK,而我们的项目采用的编程语言是 Golang,此时通常的集成方法是使用 C++ 或 Java 实现一个服务,然后在 Golang 项目里通过 RPC 调用服务,不过如此一来明显增加了系统的复杂度,好在 Golang 支持 CGO,让我们可以很方便的在 Golang 中使用 C 模块,本文总结了我在学习 CGO 过程中的心得体会。

继续阅读

浅谈pprof

对于大多数 Gopher 而言,一般平时最主要的工作内容除了实现各种无聊的业务逻辑之外,剩下的就是解决各种琐碎的问题。比如:查询性能瓶颈在哪里?查询内存泄漏在哪里?好在 pprof 是处理此类问题的利器,共有两套标准库,分别适用于不同的场景:

命令行工具「go test」就包含了 runtime/pprof,相关参数请参考「go help testflag」:

shell> go test -cpuprofile cpu.out -memprofile mem.out -bench .

不过和 runtime/pprof 相比,更常用的是 net/http/pprof,接下来我们主要通过它来解决一些常见问题,想要激活 net/http/pprof 的话很简单,只要导入对应的包并启动服务即可:

import _ "net/http/pprof"

func main() {
	_ = http.ListenAndServe("localhost:6060", nil)
}

需要注意的是,千万别让外网访问到 pprof,否则可能会导致出现安全问题。有兴趣的读者可以尝试通过 google 搜索「intitle:/debug/pprof/ inurl:/debug/pprof/」看看反面例子。

继续阅读