• go进阶笔记


    go常用包及组件

    wrap errors

    wrap errors 会把底层的所有错误(包括根源错误以及堆栈信息)打包,在顶层一次性打印出来。这样我们就不用在每一层都做日志输出和错误处理,也保证了一次错误只打印一次错误日志。

    %v 和%+v

    %v 只输出字段的value

    %+v 会以键值对的形式输出字段的key和value

    一般在程序代码(自己项目)中和第三方库、标准库、kit库(代码基础库)交互才调用wrap errors;包内的调用不会用wrap errors,避免用户也使用wrap errors造成日志的双倍打印,往往采用降级或者往上抛的处理方式。

    最底层的调用会保存整个调用过程的堆栈信息,所以只需要在出错的地方调用一次error即可获取完整的堆栈。

    sync.Pool

    sync.Pool:用于高频内存分配场景,保存和复用临时对象,可以减少内存分配,降低GC压力,只能存放一些可被随时回收的对象。

    Context

    处理请求时往往会额外开启goroutine来向后端请求数据,为了控制这些goroutine的生命周期,或者向这些goroutine传入信息,引出了context包。

    作用:传递数据,超时控制,取消goroutine。

    内存重排

    CPU/编译器 为了提高运行速率会对代码进行重排,重排后,单线程下不会影响运行结果(不会出现逻辑错误),但是多个goroutine下,就可能会出现错误。

    go内存模型(memory model)

    在cpu和内存之间有多级cache,cpu运行的数据不会立即写到内存中,而是会写入cpu的cacheline中,接着返回继续执行下一条指令。这就导致在数据写到内存前,不同goroutine之间的数据存在不可见性。

    机器字(single machine word)

    机器字由操作系统决定,是机器一次读写的位数,32位操作系统是32bit -> 4byte,64位操作系统是8byte。超过机器字大小的变量的读写不是原子的,编译的顺序由于内存重排是不确定的。

    内存可见性:由于内存重排的存在,即便是原子读写也不一定是可见的。

    内存屏障(memory barrier)

    memory barrier会使得数据在写入到cacheline后,立马扩散到内存,之后再执行其他对内存的操作。这样就保证了多个goroutine之间数据可见。

    使用os.exit()退出后,defer不会执行。

    在创建goroutine时,它的生命周期要明确,要有安全关闭的手段。

    goroutine做并发时,要由调用者自己来开,函数的提供者不应该假设这种并发情况。

    interface类型和string类型

    interface(接口)类型:包含两个指针:Type(指向实现接口的struct)和Data(指向实际的值)

    type struct{

            Type uintptr

            Data uintptr

    }

    string类型包含两个成员:指向byte数组的指针和长度(int类型)

    如何加锁?

    最晚加锁,最早释放,锁里面的内容越少越好(临界区的内容越少越好)

    COW(copy -on-write)问题

    写时复制容易出现资源竞争问题,常用Atomic(原子替换)来解决写时复制时读多写少的情况。
    具体方法:写操作时复制全量老数据到一个新的对象中,携带上本次新写的数据,之后利用原子替换。

    锁饥饿:指某个goroutine很可能长时间取不到锁。

  • 相关阅读:
    vue3解决elementPlus table组件数据量大时的卡顿问题
    逐鹿澳洲市场 宁德时代储能全场景解决方案亮相澳大利亚全能源展
    LAMP架构部署
    Android:如何在 android constraintLayout 中设置视图的最大宽度?
    Jupyter的下载与安装
    Android 在自己的项目中接入OpenCV+YOLOv8+NCNN : 实现人像分割
    磁钢的居里温度和工作温度
    正则验证用户名和跨域postmessage
    安装r包时报错:JSON:EXPECTED value GOT R
    Python实现的快速排序代码
  • 原文地址:https://blog.csdn.net/shade7/article/details/124389389