Go必知必会五连问
1.值类型有哪些?
基本数据类型都是值类型,包括:int系列、float系列、bool、字符串、数组、结构体struct。
2.引用类型有哪些?
指针、切片slice、接口interface、管道channel
3.值类型和引用类型的区别?
- 值类型在内存中存储的是值本身,而引用类型在内存中存储的是值的内存地址。
- 值类型内存通常在栈中分配,引用类型内存通常在堆中分配。
4.垃圾回收
引用类型的内存在堆中分配,当没有任何变量引用堆中的内存地址时,该内存地址对应的数据存储空间就变成了垃圾,就会被GO语言的GC回收。
5.栈,堆,切片
- 栈
在Go中,栈的内存是由编译器自动进行分配和释放,栈区往往存储着函数参数、局部变量和调用函数帧,它们随着函数的创建而分配,函数的退出而销毁。
一个goroutine对应一个栈,栈是调用栈(call stack)的简称。一个栈通常又包含了许多栈帧(stack frame),它描述的是函数之间的调用关系,每一帧对应一次尚未返回的函数调用,它本身也是以栈形式存放数据。
- 堆
与栈不同的是,应用程序在运行时只会存在一个堆。狭隘地说,内存管理只是针对堆内存而言的。程序在运行期间可以主动从堆上申请内存,这些内存通过Go的内存分配器分配,并由垃圾收集器回收。
- 切片
切片之间是不能比较的,我们不能使用==操作符来判断两个切片是否含有全部相等元素。切片唯一合法的比较操作是和nil比较。
Go必知必会力扣每日一题
《剑指 Offer 09. 用两个栈实现队列》
题目:用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail
和 deleteHead
,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead
操作返回 -1 )
解题思路:首先我们知道,队列是先入先出,栈是后入先出,所以知道了这两个东西的特性,我们很容易就能根据题意使用两个栈来模拟队列。
首先,两个栈分工不同,一个为入队栈,一个为出队栈,各自负责入队和出队。
入队操作,直接压入入队栈即可,出队操作需要优先检查出队栈是否有数据,若无,需要从入队栈倒入后再操作。
Go必知必会思路图解:
Go语言代码题解:
type CQueue struct { stack1, stack2 []int } func Constructor() CQueue { //返回一个新的CQueue return CQueue{} } //AppendTail 在stack1存入元素 func (this *CQueue) AppendTail(value int) { //在stack1 的末尾追加元素 this.stack1 = append(this.stack1, value) } //DeleteHead 从队列取出并删除 func (this *CQueue) DeleteHead() int { //如果stack2里也没有元素,则从stack1中取元素 if len(this.stack2) == 0 { //如果stack1里也没有元素,则返回-1 if len(this.stack1) == 0 { return -1 } //将stack1的所有元素转移到stackB for len(this.stack1) >0 { //获取stack1最末尾的下标 tail :=len(this.stack1)-1 //获取stack1最末尾的元素的值 value :=this.stack1[tail] //向stack2的末尾添加该元素 this.stack2 =append(this.stack2,value) //从stack1中裁剪末尾元素 this.stack1 =this.stack1[:tail] } } //这个时候Stack2内已有元素 //获取stack2最末尾的元素下标 tail :=len(this.stack2)-1 //获取stack2的最后一个元素 value :=this.stack2[tail] //从stack裁剪出末尾元素 this.stack2 =this.stack2[:tail] //返回末尾元素 return value }
go面试题并进行解答(go并发编程)
1、Mutex 有哪几种状态?
mutexLocked — 表示互斥锁的锁定状态;
mutexWoken — 表示从正常模式被从唤醒;
mutexStarving — 当前的互斥锁进入饥饿状态;
waitersCount — 当前互斥锁上等待的 Goroutine 个数;
2、Mutex 正常模式和饥饿模式分别是指什么?正常模式(非公平锁)
正常模式下,所有等待锁的 goroutine 按照 FIFO(先进先出)顺序等待。唤醒的goroutine不会直接拥有锁,而是会和新请求 goroutine 竞争锁。新请求的 goroutine 更容易抢占:因为它正在 CPU 上执行,所以刚刚唤醒的 goroutine有很大可能在锁竞争中失败。在这种情况下,这个被唤醒的 goroutine 会加入到等待队列的前面。饥饿模式(公平锁)
为了解决了等待 goroutine 队列的长尾问题,饥饿模式下,直接由 unlock 把锁交给等待队列中排在第一位的 goroutine (队头),同时,饥饿模式下,新进来的 goroutine 不会参与抢锁也不会进入自旋状态,会直接进入等待队列的尾部。这样很好的解决了老的 goroutine 一直抢不到锁的场景。饥饿模式的触发条件:当一个 goroutine 等待锁时间超过 1 毫秒时,或者当前队列只剩下一个 goroutine 的时候,Mutex 切换到饥饿模式。总结对于两种模式,正常模式下的性能是最好的,goroutine 可以连续多次获取锁,饥饿模式解决了取锁公平的问题,但是性能会下降,这其实是性能和公平的一个平衡模式。3、Mutex 允许自旋的条件的是什么?锁已被占用,并且锁不处于饥饿模式。积累的自旋次数小于最大自旋次数(active_spin=4)1.CPU 核数大于 1;2.有空闲的 P;3.当前 Goroutine 所挂载的 P 下,本地待运行队列为空。4、RWMutex怎么实现?通过记录 readerCount 读锁的数量来进行控制,当有一个写锁的时候,会将读锁数量设置为负数 1<<30。目的是让新进入的读锁等待之前的写锁释放通知读锁。同样的当有写锁进行抢占时,也会等待之前的读锁都释放完毕,才会开始进行后续的操作。而等写锁释放完之后,会将值重新加上1<<30,并通知刚才新进入的读锁rw.readerSem,两者互相限制。
分享工作生活随笔
只是因为自己不够优秀,所以只能风雨兼程,希望每天的成长,从我们彼此的分享开始。疫情当下,让我们先静心沉淀自己,当机会来临时能够一把抓的住。送给大家一句我很喜欢的话:“慢慢走,本来就很快。”,如果喜欢博主的文章请分享点赞加关注,欢迎投稿,加入Go必知必会,一起构建golang最强开放社区。
分享一个好用的包
github.com/ahmetb/go-linq/v3
用于数据的聚合,源于C#,贼像mysql的用法,用起来也很好使,有兴趣的可以B站找视频,或者看go-linq的文章,会很有收获。
文档地址:
https://pkg.go.dev/github.com/ahmetb/go-linq#section-documentation