golang-冷知识

golang垃圾回收
1:存在STW的三色标记法
程序起初创建的对象都设为白色
GC开始时从根结点开始遍历所有对象,把遍历(非递归遍历)到的对象从白色标记为灰色
遍历灰色对象,将灰色对象引用的对象标记为灰色,同时将该灰色对象标记为黑色
重复上一步骤,直到没有灰色标记的对象
将剩余所有白色结点进行删除回收

2:强-弱三色不变式
2.1强三色不变式
强制不允许黑色对象引用白色对象
2.2弱三色不变式
所有被黑色对象引用的白色对象都被灰色对象保护着

变量内存分配逃逸分析
Go 中变量分配在堆还是栈上是由编译器决定的,这种由编译器决定内存分配位置的方式称之为逃逸分析(escape analysis)。Go 中声明一个函数内局部变量时,当编译器发现变量的作用域没有逃出函数范围时,就会在栈上分配内存,反之则分配在堆上,逃逸分析由编译器完成,作用于编译阶段。

函数使用值与指针返回时性能的差异

在函数中定义变量并使用值返回时,该变量会在栈上分配内存,函数返回时会拷贝整个对象,使用指针返回时变量在分配内存时会逃逸到堆中,返回时只会拷贝指针地址,最终变量会通过 Go 的垃圾回收机制回收掉。

那在函数中返回时是使用值还是指针,哪种效率更高呢,虽然值有拷贝操作,但是返回指针会将变量分配在堆上,堆上变量的分配以及回收也会有较大的开销。对于该问题,跟返回的对象和平台也有一定的关系,不同的平台需要通过基准测试才能得到一个比较准确的结果。

缓冲通道

1、无缓冲:
要求发送方和接收方的goroutine同时准备好,才能完成发送和接收操作。
如果两个goroutine都没有准备好,通道会导致先执行发送或者接收的goroutine阻塞等待,这种对通道进行发送跟接收的交互行为本身就是同步的。

2:有缓冲的通道:make 函数创建缓冲信道指定容量
缓冲信道的容量:
是指信道可以存储的值的数量。我们在使用 make 函数创建缓冲信道的时候会指定容量大小。

读已经关闭的channel无影响。

如果在关闭前,通道内部有元素,会正确读到元素的值;如果关闭前通道无元素,则会读取到通道内元素类型对应的零值。

若遍历通道,如果通道未关闭,读完元素后,会报死锁的错误。

fatal error: all goroutines are asleep - deadlock!

写已关闭的通道

会引发panic: send on closed channel

从已关闭的 channel 接收数据,有缓冲通道返回已缓冲数据 无缓冲通道返回零值。

GMP

Go使用的是GMP模型,由GM模型演变而来

  • G:Goroutine
  • M:Machine,操作系统的执行线程
  • P:调度器,处理M与G的关系
     

G

  • 类似操作系统中的线程
  • 提供于用户态,粒度更小,切换代价更小
  • 占用空间更小,切换代价更小

M

  • P最多可以创建10000个线程
  • 最多只有GOMAXPROCS个活跃线程(与核数一致),这样不会频繁地切换线程上下文

P

  • 调度线程上执行的G,可以让出那些等待资源(如网络、IO)的G,提高运行效率
  • 同时提供M执行所需要的上下文环境以及资源

Golang锁

golang中的锁分为互斥锁、读写锁、原子锁即原子操作。在 Golang 里有专门的方法来实现锁,就是 sync 包,这个包有两个很重要的锁类型。一个叫 Mutex, 利用它可以实现互斥锁。一个叫 RWMutex,利用它可以实现读写锁。

全局锁 sync.Mutex,是同一时刻某一资源只能上一个锁,此锁具有排他性,上锁后只能被此线程使用,直至解锁。加锁后即不能读也不能写。全局锁是互斥锁,即 sync.Mutex 是个互斥锁。

读写锁 sync.RWMutex ,将使用者分为读者和写者两个概念,支持同时多个读者一起读共享资源,但写时只能有一个,并且在写时不可以读。理论上来说,sync.RWMutex 的 Lock() 也是个互斥锁。

踩坑点
将上面的结论展开一下,更清晰得说(为避免理解偏差宁可唠叨一些):

sync.Mutex 的锁是不可以嵌套使用的。
sync.RWMutex 的 mu.Lock() 是不可以嵌套的。
sync.RWMutex 的 mu.Lock() 中不可以嵌套 mu.RLock()。(这是个注意的地方)

进程,线程,协程
进程是操作系统资源分配的基本单位
线程是操作系统调度到CPU中执行的基本单位
线程是根据CPU时间片进行抢占式调度的  操作系统用户态与内核态的切换、默认的栈大小一般为8MB
协程存在于用户态,由go语言运行时调度器进行调度  不需要经过用户态与内核态的切换、go协程栈大小默认为2KB


安全类型

slice和map不是协程安全的需要加锁mutex,channel、指针、函数是协程安全的。

 context
context 主要用来在 goroutine 之间传递上下文信息,包括:取消信号、超时时间、截止时间、k-v 等


WithValue 创建 context 节点的过程实际上就是创建链表节点的过程。两个节点的 key 值是可以相等的,但它们是两个不同的 context 节点。查找的时候,会向上查找到最后一个挂载的 context 节点,也就是离得比较近的一个父节点 context。所以,整体上而言,用 WithValue 构造的其实是一个低效率的链表。

并发执行子任务且限制并发数

/*有编号为1-100 的共100个任务,每个任务打印一次 自己的编号即可,请实现如何让100个任务并发执行,但是同一时刻最多运行10个任务*/
func main () {
   var wg sync.WaitGroup//保证当前进程同步进行
   sem := make(chan struct{},10)//保证10个一组并发执行,但是不会超过该缓冲区
   for i:=1 ;i <=100 ; i++ {
      wg.Add(1)
      go func(i int) {
         defer wg.Done()
         sem <- struct{}{}//写入缓冲区
         fmt.Println(i)
         defer func() {<-sem}()//取出缓冲区
      }(i)
   }
   wg.Wait()//知道group计数器从100减到0  done就是add(-1)
   close(sem)
}

defer 面试题
defer是延迟函数,执行动作在return之后,defer相当于是将执行动作压入栈中,越是后面的defer越是先执行,执行顺序是LIFO(后进先出) ,defer可以修改函数最终返回值。 作者:亦一银河 https://www.bilibili.com/read/cv12597493 出处:bilibili

 

func deferFunc1(i int) (t int) {
    t = i
    defer func() {
        t += 1
    }()
    return t
}

func deferFunc2(i int) int {
    t := i
    defer func() {
        t += 1
    }()
    return t
}

func deferFunc3(i int) (t int) {
    defer func() {
        t += i
    }()
    return 1
}

func deferFunc4() (t int) {
    defer func(i int) {
        fmt.Println(i)
        fmt.Println(t)
    }(t)
  t = 0
    return 1
}

func ExecDeferFunc() {
  // 猜猜下面输出的内容和顺序
    fmt.Println(deferFunc1(1))
    fmt.Println(deferFunc2(1))
    fmt.Println(deferFunc3(1))
    deferFunc4()
}
『实际结果是:2,1,2,0,1
deferFunc1  由于t作用于在函数中且作为返回值,所以,先return修改函数返回值t为1 然后defer 再接收到t并+1返回2
deferFunc2  由于t作用于在函数中但是不作为返回值,所以,defer 接收到t为0+1返回1
deferFunc3  由于t作用于在函数中且作为返回值,所以,先return修改函数返回值t为1 然后defer 再接收到t并+1返回2
deferFunc4  由于i没有定义defer打印为默认值0  而t在函数返回值被赋值为1 然后传入defer中打印为1

Gin洋葱模型

make和new的区别
make和new都是内存的分配(堆上),但是make只用于slice、map以及channel的初始化(非零值);而new用于类型的内存分配,并且内存置为零。make返回的是引用类型本身;而new返回的是指向类型的指针

range中文字符串

golang中序遍历

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值