func (c *conn) setState(nc net.Conn, state ConnState) {
...
c.curState.Store(connStateInterface[state])
...
}
// connStateInterface is an array of the interface{} versions of
// ConnState values, so we can use them in atomic.Values later without
// paying the cost of shoving their integers in an interface{}.
var connStateInterface = [...]interface{}{
StateNew: StateNew,
StateActive: StateActive,
StateIdle: StateIdle,
StateHijacked: StateHijacked,
StateClosed: StateClosed,
}
Run Code Online (Sandbox Code Playgroud)
我无法弄清楚connStateInterface的技巧,它究竟是如何工作的?
这里有一些事情......
该[...]声明创建实际的阵列,而不是一个切片,以使得间接被去除.这里宣布的是一系列interface{}类型......所以你可能想知道为什么奇怪的地图符号?
该StateXXX变量只是上面进一步声明的常量,所以他们是整数...这样的声明实际上是形式为index: value.
这是使用一组int的一个不太模糊的例子:
var i = [...]int{4: 2, 2: 7}
Run Code Online (Sandbox Code Playgroud)
这将分配一个包含:
[0, 0, 7, 0, 2]
Run Code Online (Sandbox Code Playgroud)
...注意索引2有7,索引4有2.不是一种声明数组的常用方法,但它是有效的Go.
所以回到原始声明,只需要我上面给出的例子,而不是int,创建类型的数组interface{}:
var i = [...]interface{}{4: 2, 2: 7}
Run Code Online (Sandbox Code Playgroud)
你会得到一个类似的数组,但nil接口值代替零.
更接近原始代码,StateXXX常量只是整数,而不是像我的例子中的文字.
那么,这一切有什么意义呢?为什么所有的混淆?
这是一次表演黑客攻击.该函数c.curState.Store()采用类型的参数interface{}.如果你要传递一个int,那么编译后的代码就必须在每次调用时转换类型.一个更清晰(但显然不切实际)的例子可能是:
var val interface{}
for i := 0; i < 1000000; i++ {
// the types are different, compiler has to fumble int vs. interface{}
val = i
// do something with val
}
Run Code Online (Sandbox Code Playgroud)
每次你进行val = i转换int和interface{}需要发生.您发布的代码通过创建静态查找表来避免这种情况,其中所有值都已经是接口类型.
因此,这个:
c.curState.Store(connStateInterface[state])
Run Code Online (Sandbox Code Playgroud)
比这更有效:
c.curState.Store(state)
Run Code Online (Sandbox Code Playgroud)
由于state会,在这种情况下,需要进行的int -> interface{}转换.在优化代码中,state仅仅是一个将值查找到数组中的索引,其结果会使您获得interface{}...因此int -> interface{}可以避免类型转换.
我不熟悉那些代码,但我认为它处于一个关键的路径中,纳秒或任何节省的成本可能会产生影响.