golang知识点

时间:2025-03-30 18:10:04

1. golang中安全读写共享变量

  1. 通过Channel进行安全读写共享变量

  2. 通过Mutex加锁处理

  3. 对于Map可以使用

  4. 针对读多写少情况可以使用

2. channel是否同步问题

  1. channel无缓冲时,发送阻塞直到数据被接收,接收阻塞直到读取到数据
  2. channel有缓冲时,当缓冲满时发送阻塞,当缓冲空时接收阻塞

3. go语言并发机制以及它所使用的CSP并发模型

  • CSP模型是上个世纪七十年代提出的,不同于传统的多线程通过共享内存来通信,CSP讲究的是“以通信的方式来共享内存”。用于描述两个独立的并发实体通过共享的通讯 channel(管道)进行通信的并发模型。 CSP中channel是第一类对象,它不关注发送消息的实体,而关注与发送消息时使用的channel。
  • Golang中channel 是被单独创建并且可以在进程之间传递,它的通信模式类似于 boss-worker 模式的,一个实体通过将消息发送到channel 中,然后又监听这个 channel 的实体处理,两个实体之间是匿名的,这个就实现实体中间的解耦,其中 channel 是同步的一个消息被发送到 channel 中,最终是一定要被另外的实体消费掉的,在实现原理上其实类似一个阻塞的消息队列。
  • Goroutine 是Golang实际并发执行的实体,它底层是使用协程(coroutine)实现并发,coroutine是一种运行在用户态的用户线程,类似于 greenthread,go底层选择使用coroutine的出发点是因为,它具有以下特点:

  1. 用户控件避免了内核态和用户态的切换导致的成本

  2. 可以由语言和框架层进行调度

  3. 更小的栈空间允许创建大量的实例

  • Golang中的Goroutine的特性:

  • Golang内部有三个对象:P对象(processor)代表上下文(或者认为是cpu),M(work thread)代表工作线程,G对象(goroutine)

  • Goroutine 是Go语言中并发的执行单位。有点抽象,其实就是和传统概念上的”线程“类似,可以理解为”线程“。 Channel是Go语言中各个并发结构体(Goroutine)之前的通信机制。通常Channel,是各个Goroutine之间通信的”管道“,有点类似于Linux中的管道。

4. Golang中常用的并发模型

  • 通过channel通知实现并发控制
  • 通过实现并发控制
  • 通过Context上下文实现并发控制

5. JSON标准库对nil slice和空slice的处理是一致的么

  • nil slice是slice是nil,如只是声明并没有实例化
  • empty slice是列表已经make实例化,但是里边并没有值

6. 协程、进程、线程区别

  • 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全。
  • 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。
  • 协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

7. 互斥锁、读写锁,死锁问题是怎么解决的

  • 互斥锁就是互斥变量mutex,用来锁住临界区
  • 读写锁,可以同时存在多个读锁,当写锁出现时其他代码都不可获取锁,直到锁打开
  • 注意:写独占,读共享,写锁享有最高优先级
  • 死锁产生的四个必要条件:
  1. 互斥条件:一个资源每次只能被一个进程使用
  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  3. 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺。
  4. 循环等待条件:若干进程之间形成一种头尾详解的循环等待资源关系。

    a. 预防死锁

    可以把资源一次性分配:(破坏请求和保持条件)

    然后剥夺资源:即当某进程新的资源未满足时,释放已占有的资源(破坏不可剥夺条件)

    资源有序分配法:系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反(破坏环路等待条件)

    b. 避免死锁

    预防死锁的几种策略,会严重地损害系统性能。因此在避免死锁时,要施加较弱的限制,从而获得 较满意的系统性能。由于在避免死锁的策略中,允许进程动态地申请资源。因而,系统在进行资源分配之前预先计算资源分配的安全性。若此次分配不会导致系统进入不安全状态,则将资源分配给进程;否则,进程等待。其中最具有代表性的避免死锁算法是银行家算法。

    c. 检测死锁

    首先为每个进程和每个资源指定一个唯一的号码,然后建立资源分配表和进程等待表.

    d. 解除死锁

    当发现有进程死锁后,便应立即把它从死锁状态中解脱出来,常采用的方法有.

    e. 剥夺资源

    从其它进程剥夺足够数量的资源给死锁进程,以解除死锁状态.

    f. 撤消进程

    可以直接撤消死锁进程或撤消代价最小的进程,直至有足够的资源可用,死锁状态.消除为止.所谓代价是指优先级、运行代价、进程的重要性和价值等。

8. Golang的内存模型,为什么小对象多了会造成gc压力

  • 通常小对象过多会知道GC三色法消耗过多的GPU。优化思路是减少对象分配。

9. 什么事Channel,为什么它可以做到线程安全

  • Channel是Go中的一个核心类型,可以把它看成一个管道,通过它并发核心单元就可以发送或者接受数据进行通讯,Channel也可以理解是一个先进先出的队列,通过管道进行通讯。
  • Golang的Channel,发送一个数据到Channel和从Channel接收一个数据都是原子性的。而且Go的设计思想就是:不要通过共享内存来通信,而是通过通信来共享内存,前者就是传统的加锁,后者就是Channel。也就是说,设计Channel的主要目的就是在多任务间传递数据的,这当然是安全的。

10.