💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
## 一、Golang Slice的扩容机制,有什么注意点? #### 1、Go 中切片扩容策略: * 首先判断,如果新申请容量大于2倍的旧容量,最终容量就是新申请的容量 * 否则判断,如果旧切片的长度小于1024,则最终容量就是旧容量的两倍 * 否则判断,如果旧切片长度大于等于1024,则最终容量从旧容量开始循环增加原来的 1/4, 直到最终容量大于等于新申请的容量 * 如果最终容量计算值溢出,则最终容量就是新申请容量 #### 2、扩容前后的Slice是否相同? * 情况一: 原数组还有容量可以扩容(实际容量没有填充完),这种情况下,扩容以后的数组还是指向原来的数组,对一个切片的操作可能影响多个指针指向相同地址的Slice。 * 情况二: 原来数组的容量已经达到了最大值,再想扩容, Go 默认会先开一片内存区域,把原来的值拷贝过来,然后再执行 append() 操作。这种情况丝毫不影响原数组。 要复制一个Slice,最好使用Copy函数。 ## 二、互斥锁,读写锁,死锁问题是怎么解决 * 互斥锁 互斥锁就是互斥变量mutex,用来锁住临界区的. 条件锁就是条件变量,当进程的某些资源要求不满足时就进入休眠,也就是锁住了。当资源被分配到了,条件锁打开,进程继续运行;读写锁,也类似,用于缓冲区等临界资源能互斥访问的。 * 读写锁 通常有些公共数据修改的机会很少,但其读的机会很多。并且在读的过程中会伴随着查找,给这种代码加锁会降低我们的程序效率。读写锁可以解决这个问题。 [![](https://github.com/KeKe-Li/golang-interview-questions/raw/master/src/images/61.jpg)](https://github.com/KeKe-Li/golang-interview-questions/blob/master/src/images/61.jpg) 注意:写独占,读共享,写锁优先级高 * 死锁 一般情况下,如果同一个线程先后两次调用lock,在第二次调用时,由于锁已经被占用,该线程会挂起等待别的线程释放锁,然而锁正是被自己占用着的,该线程又被挂起而没有机会释放锁,因此就永远处于挂起等待状态了,这叫做死锁(Deadlock)。 另外一种情况是:若线程A获得了锁1,线程B获得了锁2,这时线程A调用lock试图获得锁2,结果是需要挂起等待线程B释放锁2,而这时线程B也调用lock试图获得锁1,结果是需要挂起等待线程A释放锁1,于是线程A和B都永远处于挂起状态了。 死锁产生的四个必要条件: 1. 互斥条件:一个资源每次只能被一个进程使用 2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。 3. 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。 4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。 这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。 a. 预防死锁 可以把资源一次性分配:(破坏请求和保持条件) 然后剥夺资源:即当某进程新的资源未满足时,释放已占有的资源(破坏不可剥夺条件) 资源有序分配法:系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反(破坏环路等待条件) b. 避免死锁 预防死锁的几种策略,会严重地损害系统性能。因此在避免死锁时,要施加较弱的限制,从而获得 较满意的系统性能。由于在避免死锁的策略中,允许进程动态地申请资源。因而,系统在进行资源分配之前预先计算资源分配的安全性。若此次分配不会导致系统进入不安全状态,则将资源分配给进程;否则,进程等待。其中最具有代表性的避免死锁算法是银行家算法。 c. 检测死锁 首先为每个进程和每个资源指定一个唯一的号码,然后建立资源分配表和进程等待表. d. 解除死锁 当发现有进程死锁后,便应立即把它从死锁状态中解脱出来,常采用的方法有. e. 剥夺资源 从其它进程剥夺足够数量的资源给死锁进程,以解除死锁状态. f. 撤消进程 可以直接撤消死锁进程或撤消代价最小的进程,直至有足够的资源可用,死锁状态.消除为止.所谓代价是指优先级、运行代价、进程的重要性和价值等。 ## 三、什么是channel,为什么它可以做到线程安全? Channel是Go中的一个核心类型,可以把它看成一个管道,通过它并发核心单元就可以发送或者接收数据进行通讯(communication),Channel也可以理解是一个先进先出的队列,通过管道进行通信。 Golang的Channel,发送一个数据到Channel 和 从Channel接收一个数据 都是 原子性的。而且Go的设计思想就是:不要通过共享内存来通信,而是通过通信来共享内存,前者就是传统的加锁,后者就是Channel。也就是说,设计Channel的主要目的就是在多任务间传递数据的,这当然是安全的。 ## 四、垃圾处理 [https://github.com/KeKe-Li/For-learning-Go-Tutorial/blob/master/src/spec/02.0.md](https://github.com/KeKe-Li/For-learning-Go-Tutorial/blob/master/src/spec/02.0.md) ## 五、并发编程概念是什么? 并行是指两个或者多个事件在同一时刻发生;并发是指两个或多个事件在同一时间间隔发生。 并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。在一台处理器上“同时”处理多个任务,在多台处理器上同时处理多个任务。如hadoop分布式集群 并发偏重于多个任务交替执行,而多个任务之间有可能还是串行的。而并行是真正意义上的“同时执行”。 并发编程是指在一台处理器上“同时”处理多个任务。并发是在同一实体上的多个事件。多个事件在同一时间间隔发生。并发编程的目标是充分的利用处理器的每一个核,以达到最高的处理性能。