zoukankan      html  css  js  c++  java
  • Slices instead of maps for (key -> value) entries

    今天看了下fasthttp的源码,发现了一个有趣的地方,遂研究了一下。

    详情请直接看原作者的一个slides

    https://docs.google.com/presentation/d/e/2PACX-1vTxoBN41dYFB8aV8c0SDET3B2htsAavXPAwR-CMyfT2LfARR2KjOt8EPIU1zn8ceSuxrL8BmkOqqL_c/pub?start=false&loop=false&delayms=3000&slide=id.g524654fd95_0_111

    这里简单分析一下为何这么替换和替换的一些细节。

    第一眼看下来,what,哪边复用,有什么精妙的,但是要结合场景考虑,这个是专门为net.http写的,每一次请求它是不同的。

    fasthttp中的reset思路是

    sm=sm[:0]

    不是我们一般习惯的

    sm=nil

    由于切片的源码是

    // runtime/slice.go
    type slice struct {
        array unsafe.Pointer // 数组指针
        len   int // 长度 
        cap   int // 容量
    }

    可见,这种思路完全是复用底层内存的,但是仅仅如此吗?作者还有个很精妙的地方

    就是扩容,这种扩容是持久的,上一个请求的sliceMap够用,这个不够用了,ok,扩容,下一个如果和上一个相同的需求,不需要再次扩容了,一个服务的异样请求统共不会太多,所以一段时间后就基本不会发生扩容了。

    这里的kv.key和kv.value,在前面的基础上就使用的是append(s[:0], k...)这种思路,你这里可能会问这不是发生string和slice的转换吗,如果看汇编的话,这种操作是会进行编译优化的。

    没有call stringtoslice,性能是可以保证的。

    源码示例

    type argsKV struct {
        key     []byte
        value   []byte
        noValue bool
    }
    
    // 增加新的kv
    func appendArg(args []argsKV, key, value string, noValue bool) []argsKV {
        var kv *argsKV
        args, kv = allocArg(args)
        // 复用原来key的内存空间
        kv.key = append(kv.key[:0], key...)
        if noValue {
            kv.value = kv.value[:0]
        } else {
            // 复用原来value的内存空间
            kv.value = append(kv.value[:0], value...)
        }
        kv.noValue = noValue
        return args
    }
    
    func allocArg(h []argsKV) ([]argsKV, *argsKV) {
        n := len(h)
        if cap(h) > n {
            // 复用底层数组空间,不用分配
            h = h[:n+1]
        } else {
            // 空间不足再分配
            h = append(h, argsKV{})
        }
        return h, &h[n]
    }

     至于别的区别,可以看slice和map的源码,首先两者的struct就能看出这种方式的优点。

    不过,话转回来,这好像让编程变得更麻烦了点,因为golang的设计就是不推荐走手动管内存的。如果没有性能瓶颈,还是建议采用Golang核心队伍的的思路。

    一个没有高级趣味的人。 email:hushui502@gmail.com
  • 相关阅读:
    v-cloak
    MVVM
    初识ajax
    装瓶学习法
    回调函数(call back)
    如何让学习变得纯粹?
    异步
    grep用法
    Shell中的&&与||的区别
    shell中使用>/dev/null 2>&1 丢弃信息
  • 原文地址:https://www.cnblogs.com/CherryTab/p/12849676.html
Copyright © 2011-2022 走看看