北京专门做seo,seo中文意思,wordpress 配置证书,广州市住房和城乡建设局1. go语言有哪些优点、特性#xff1f;
语法简便#xff0c;容易上手。
支持高并发#xff0c;go有独特的协程概念#xff0c;一般语言最小的执行单位是线程#xff0c;go语言支持多开协程#xff0c;协程是用户态线程#xff0c;协程的占用内存更少#xff0c;协程只…1. go语言有哪些优点、特性
语法简便容易上手。
支持高并发go有独特的协程概念一般语言最小的执行单位是线程go语言支持多开协程协程是用户态线程协程的占用内存更少协程只独有自己的栈等一些资源。其他都是共享线程的。调度时可以极大减少上下文切换。
2. go的包管理
golang在1.11版本之前用的是GOPATH项目代码要放在GOPATH/src目录下才可运行。但是GOPATH存在弊端没有版本控制概念go get的外部库自己都不知道下载的什么版本再多人协作开发时无法确定大家的外部库版本是否一致会出大问题。
golang1.11后推荐使用go mod 管理go env 下设置 GO111MODULE on 打开。支持依赖升降级。 3. make和new 的一些区别
new 可以初始化声明所有类型返回的是一个指针类型。对应的是该类型的空值
make 只能用来初始化 map slice channel 的返回的就是这个类型。对应的是该类型的零值
new的用法不常见一般使用 var 或 : 4. channel 是可以被 close 的之后还可以读写吗
不管是有无缓冲channel。关闭后都可以读如果缓冲区里还有数据先将缓冲区数据读完后在读读的是channel 传输类型的 零值。
不管是有无缓冲channel关闭后都不可以写写会panic 5. channel有什么用
channel 用来做协程之间的通信。go语言提倡不要用共享内存来通信要用通信的方式来共享内存。channel就是利用通信的方式实现对资源的访问。
无缓冲channel可以用来做协程间的同步
有缓冲channel可以用来做消息队列 6. channel的底层结构接收、发送消息的过程
channel底层是一个结构体里面包含一个环形缓冲区还有接收等待队列和发送等待队列。分别存放等待写消息的协程队列和读消息的协程队列还有一个互斥锁用来保证channel的线程安全防止多个协程并发读写可能导致的问题。
当一个协程向channel写数据如果是无缓冲通道会将其加入到消息等待发送队列中等待一个协程向channel读数据
读数据时会先看缓冲区如果没有再唤醒消息等待发送队列的第一个协程拿到信息如果没有加入到消息等待接收队列等待一个协程向channel写数据 7. channel 并发安全吗?
channel并发安全底层结构体中有一个互斥锁在并发环境下可以自动实现加锁解锁操作。 8. 怎么样输出一个有序的map
用slice存放map的key值对slice进行排序然后按照slice顺序查找map key value
用golang的数据结构 list来实现list是一个链表。map[key]value value存放链表节点写入map的时候同时按照顺序写入list中顺序遍历时只需要遍历链表即可。可以达到有序效果。 9. map在传参时的类型
golang传参都是值传递只是对于map chan 等类型他们在进行值拷贝的时候调用的makechan 和 makemap 方法返回的都是指针类型的变量。导致操作的其实是同一个内存。 10. 可以直接对map取地址吗
对map可以取址但是对于map的key value不能取址map不支持这种操作当某种条件达到后map会做增量扩容或者等量扩容操作。这时候每个key 的地址都可能发生变化。因此获取map key value地址的操作是无意义的。
11. map底层结构
map底层是一个结构体hmaphmap中包含 元素的个数桶的个数以及指向桶数组的指针每一个桶是一个bucketbucket在go中用的是 bmap结构体每个bucket可以存放 8个键值对哈希值低八位相同的键存入bucket时会将高八位存储在tophash数组里。data 区域存放的key-value数据是按照 keykeykey valuevaluevalue存放的overflow指针指向下一个bucket桶通过链表将所有冲突的键连接起来。
12. 哪些数据类型不能作为map里面的key哪些可以有没有什么评判标准
无法比较的数据类型都不能作为map里面的key。
基本数据类型都可作为key指针也可以因为指针比较的是地址。 数组也可以结构体也可以
不可比较 map slice function 13. map是并发安全的吗怎么实现并发安全
map不是并发安全的底层结构体没有用互斥锁进行加锁解锁操作。
如何实现并发安全1.map读写锁 推荐 2.用sync.Map 14. sync.Map如何解决并发问题
sync.Map底层结构体中嵌入了一个互斥锁。当某个协程对map进行写操作时会上写互斥锁其他协程看到锁于是会阻塞。当某个协程对map进行读操作时会上读锁但是读锁可以共享所以其他协程也可以对map进行读操作。 15. gmp模型局部饥饿、全局饥饿、全局缓存队列等
最开始的时候大多用线程池开一定量的线程当有工作任务到来时会拿出一个线程处理但当因为发生系统调用而阻塞时线程池中可工作的线程就少了线程池的性能就降低了。于是有了GMP模型。
G是协程用户态线程
本地队列每个P都有本地队列本地队列中存放的是G
全局队列当本地队列都满了新来的G会优先加入本地队列中本地队列满了会把本地队列的一半加入到全局队列
M是工作线程用来处理协程的
P是处理器默认数量是内核数M通过获取P来处理P中的G 15. go有了协程之后那它的线程是怎么调度的GMP模型M最多多少个
有调度策略线程正常情况下会和P绑定处理P中的本地队列G但当处理G时由于系统调用导致阻塞时会触发hand offM会和 P 解绑把P转移给其他的空闲M如果没有就创建一个新的M处理。如果M将P中的队列G处理完了就会从其他P的本地队列中偷取一半协程来运行如果其他都没有就会从全局队列中选择一批来处理。
M最多10000个在初始化运行时会设置最大值。但因为M需要获取到P才能处理GP的数量是很有限的所以M不会很多。
16. 线程数量和什么有关系线程数量是无限大的吗
线程数量和程序运行时设置的最大M有关默认是10000并且跟P有关系因为M必须要拿到P才能处理G。而且如果线程处理的阻塞的G完成后可能会被销毁。不能无限大 16. slice深度拷贝
copy方法时或者append触发扩容机制时都是深度拷贝。拷贝的是数据本身新创建的对象和源对象不共享内存会另开辟一个新的内存地址值修改时不会影响源对象值。 17. slice和数组有什么区别
slice 结构体中包含了 一个指向底层数组的指针还有slice的长度及容量
数组无法扩容切片可以动态追加
数组声明时需要指定长度切片不需要
数组是值类型的切片是引用类型的 18. slice如何扩容
1.18版本之前当切片容量1024之前每次扩容都是原来数组的二倍当切片容量到1024之后每次扩容都是原数组1.25倍
1.18版本觉得扩容比例一下从2变成1.25有些不平滑于是调整扩容机制在容量小于256时是2倍扩容当容量大于256时增加 原来容量3*256/4。逐渐接近1.25倍更平滑 19. interface{}怎么用
interface{}可以用来实现多态和符合设计模式的原则 依赖倒转 面向接口编程。 写一个接口里面有要实现的方法定义一个结构体实现接口中的方法然后初始化时声明一个接口对象并指向具体的结构体这样实现了面向接口编程解耦。
也可以用来做强制类型转换断言。interface.(type) 20. 说一下go的继承
go中的继承是通过结构体嵌套实现的子结构体嵌套父结构体。初始化子结构体后就可以用父结构体的方法。 21. go中哪些变量是不能比较的
map slice function 22. golang强类型弱类型
golang是强类型语言不会隐式的进行数据类型的转换。在速度上可能略逊弱类型语言但是严谨性又避免了不必要的错误 23. golang并发控制
可以用 Sync.WaitGroup实现 WaitGroup有三个方法Add,Done,Wait。用来控制计数器数量。
可以用channel实现goroutine之间通过channel通信如果多个goroutine都写入channel这时候通过缓冲区就可以实现并发控制当缓冲区满时后面的goroutine的写操作会被阻塞。 24. 一个go-routine最小占多大内存空间
2kb 25. context类型有哪些Context的作用是什么context如何实现cancel的
context主要用来在协程间传递关闭信号、信息的。可以控制多级协程
空context、cancelCtx、valueCtx、timerCtx。cancelCtx可以用来做协程的断开操作。 27. 正常模式和饥饿模式
针对于互斥锁的Mutex。正常模式下请求锁的协程要按照先入先出顺序排队以此被唤醒唤醒后还要与新请求锁的协程进行竞争因为新请求的协程有优势他们正在CPU上运行或者数量比较多。新唤醒的协程很难获取到锁于是又会加到队列头部如果一个等待的协程超过1ms仍未获取到锁就会进入到饥饿模式。
饥饿模式下互斥锁所有权会直接从解锁的协程转移到队首的协程并且新到达的协程不会尝试获取锁而是加到队列尾部。如果一个等待协程获取到锁并且满足下面两个条件只一就会回到正常模式。是队列的最后一个协程等待时间小于1ms。
正常模式有更好的性能饥饿模式可以避免尾部延迟这种情况 28. 用Go实现一个死锁
死锁存在四个条件互斥占有且等待循环等待不可强占用
func main() {ch1 : make(chan int)ch2 : make(chan int)var x sync.WaitGroupx.Add(2)go func() {ch2 - 1fmt.Println(-ch1)x.Done()}()go func() {ch1 - 1fmt.Println(-ch2)x.Done()}()x.Wait()
} 29. gc的了解
gc是垃圾回收机制为了对堆栈上使用完的对象及时回收。防止内存溢出。最初1.3版本之前使用的是标记清除法GC时会暂停程序进行标记清楚操作。STW时间很长。为了优化STW1.3版本后缩短了一些STW时间回收对象的操作放在STW时间之外。1.5版本时为了降低STW的时间使用三色标记法插入/删除屏障实现。三色标记法是在GC开始时从根节点开始遍历所有可达对象第一次遍历到的对象置灰第二次遍历到的对象置黑。当没有灰色对象是开始回收对象。但是这样存在问题当新创建了一个白色对象时被一个黑色对象引用了此时会造成刚创建的对象也被回收。还有当删除一个对象时但是后面的对象还想要使用但是断掉后后面的对象也会被回收。针对这两种情况提出了两个设计原则强三色不变式和弱三色不变式强三色强调黑色对象不能引用白色对象。弱三色不变式强调当黑色对象引用白色对象是要保证还有一个灰色对象引用白色对象。针对这两个原则产出了插入屏障和删除屏障插入屏障实现的是强三色不变式当黑色对象引用白色对象时会将白色对象变为灰色对象。删除屏障实现的是弱三色不变式当删除灰色后面的白色对象会把删除的白色对象置灰。当扫描完没有灰色对象后会将栈对象置白启用STW从新扫描一遍栈上的可达节点最终删掉白色对象。插入屏障仍然需要re-scan栈上的节点。删除屏障删除效率低这次要删除的对象要等下次才能删掉。于是1.8版本后采用三色标记法混合写屏障。混合写屏障结合了插入和删除屏障的优点栈上的对象不启用GC扫描时会将所有栈上对象和新建对象置黑针对堆上对象所有创建和删除的对象都置灰。体现的是变形的弱三色不变式。1.8版本极大减少了STW时间但并不是完全没有因为在GC三色标记法之前还要STW开启辅助GC和写屏障统计根对象的任务数量等。 30. 什么时候会触发 golang GC 呢
手动触发调用runtime.GC来手动触发
定期触发最长两分钟触发一次GC
内存达到一定值每当内存扩大一倍时启用GC 31. 内存泄漏
创建的资源没有正常释放造成内存一直占用。也无法被GC回收。内存泄漏一般是程序员申请资源后没有手动去释放资源关闭通道解锁等。
通过pprof工具排查 32. go里面声明一个变量它是放在栈上还是堆上
内存逃逸局部变量从栈上逃逸到堆上发生了内存逃逸。
对于指针类型因为分配内存时不知道是否存在外部引用于是就将内存分配在堆中防止函数结束后局部变量被回收。
如果数据量太大栈放不下就会逃逸到堆中
interface类型上调用方法编译时不知道是如何实现的就会放到堆中。 33. 子goroutine的panic会不会被父g捕获
panic只能捕获本协程内部的错误无法捕获子协程的错误
34. defer的先后顺序
defer满足栈的结构先入后出。
35. defer什么情况下可以修改函数的返回值
defer和return知识return分为两步操作第一步先将返回值赋给return在准备返回之前要执行defer函数执行完后才将结果返回。 如果定义了具名返回值并且在defer时对这个变量进行了处理。那return 这个变量时就会修改。 36. golang 如何做超时控制
1.timeAfter 这个函数会返回一个通道并且过一段时间后会自动向通道发送一个数据。
2.context 的 withTimeout 和 withDeadline 方法当到规定时间或超过某一时间后会调用cancel方法来关闭channel。可以做超时控制 37. select 一般使用在什么场景
select一般与通道连用用来监听多个通道的状态。
可以在多个通道中选择一个可用的操作来执行如果没有一个通道准备就绪select会执行defaule语句或者继续等待。 38.go程序运行顺序
从main包开始执行首先会导入引用的包如果这个包里有init函数会先执行这个包的init函数。
如果在main包定义了init函数Go运行会在包导入后全局变量初始化之前调用init函数。
调用之后会进行全局变量初始化操作最终进入到main函数是整个程序入口点。main函数执行后程序会按照调用函数顺序依次执行其他函数。