Go语言

Go语言中数组和切片的区别是什么?它们可以相互转化吗?

  • 切片是指针类型,数组是值类型;
  • 数组的长度是固定的,而切片不是(切片可以看成动态的数组);
  • 切片比数组多一个容量(cap)属性;
  • 切片的底层是数组。

相互转化

[:]
// 初始化一个数组
a0 := [2]int{1, 2}
// 初始化一个切片
s1 := make([]int, 5, 5)
fmt.Println(a0)
fmt.Println(s1)

// 无法将 'a0' (类型 [2]int) 用作类型 []int
// s1 = a0
// 无法将 's1' (类型 []int) 用作类型 [2]int
// a0 = s1

// 可以使用[:]方式将数组转换成切片
fmt.Println(copy(s1, a0[:]))
fmt.Println(a0)
fmt.Println(s1)

fmt.Println(copy(a0[:], s1))
fmt.Println(a0)
fmt.Println(s1)

简述Go语言中的零值

类型长度(字节)默认值(零值)说明
bool1false
byte10uint8
rune40Unicode Code Point, int32
int, uint4或8032 或 64 位
int8, uint810-128 ~ 127, 0 ~ 255,byte是uint8 的别名
int16, uint1620-32768 ~ 32767, 0 ~ 65535
int32, uint3240-21亿~ 21亿, 0 ~ 42亿,rune是int32 的别名
int64, uint6480
float3240.0
float6480.0
complex648
complex12816
uintptr4或8以存储指针的 uint32 或 uint64 整数
array值类型
struct值类型
string“”UTF-8 字符串
slicenil引用类型
mapnil引用类型
channelnil引用类型
interfacenil接口
functionnil函数

在Go语言中,Map是线程安全的吗?

sync.map

简述Go语言的GC(垃圾回收)机制

标记-清除(mark and sweep)算法(Go 1.3之前)

  1. 暂停程序业务逻辑,找出不可达对象,然后坐上标记并回收标记好的对象。
  2. 程序找出它所有可达的对象,并做上标记。
  3. 清除未标记的对象。
  4. 停止暂停,让程序继续跑。然后循环重复这个过程,直到process程序生命周期结束。

三色并发标记法(Go 1.5)

  1. 只要是新创建的对象,默认的颜色都是标记为“白色”;
  2. 每次GC回收开始,然后从根节点开始遍历所有对象,把遍历到的对象从白色集合放入“灰色”集合;
  3. 遍历灰色集合,将灰色对象引用的对象从白色集合放入灰色集合,之后将此灰色对象放入黑色集合;
  4. 重复第3步, 直到灰色中无任何对象;
  5. 回收所有的白色标记表的对象。

混合写屏障(hybrid write barrier)机制(Go 1.8)

  1. GC开始将栈上的对象全部扫描并标记为黑色(之后不再进行第二次重复扫描,无需STW)。

  2. GC期间,任何在栈上创建的新对象,均为黑色。

  3. 被删除的对象标记为灰色。

  4. 被添加的对象标记为灰色。

总结

Go 1.3 - 普通标记清除法,整体过程需要启动STW,效率极低。

Go 1.5 - 三色标记法,堆空间启动写屏障,栈空间不启动,全部扫描之后,需要重新扫描一次栈(需要STW),效率普通。

Go 1.8 - 三色标记法,混合写屏障机制,栈空间不启动,堆空间启动。整个过程几乎不需要STW,效率较高。

Go语言的并发模型有哪几种?

Go语言中实现了两种并发模型,一种线程与锁并发模型,另一种是CSP(communicating sequential processes)通信顺序进程模型

CSP 并发模型

  • 并发实体(通常可以理解为执行线程),它们相互独立(没有共享内存空间),且并发执行;
  • 并发实体之间使用通道发送信息。无论在通道中放数据还是从通道中取数据,都会导致并发实体的阻塞,直到通道中的数据被取出或者通道中被放入新的数据,并发实体通过这种方式实现同步。

线程与锁并发模型

用户级线程

用户线程由用户空间的代码创建、管理和销毁,线程的调度由用户空间的线程库完成(可能是编程语言层次的线程库),无需切换内核态,资源消耗少且高效。对 CPU 的竞争是以所属进程的维度参与的,同一进程下的所有用户级线程只能分时复用进程被分配的 CPU 时间片,所以无法很好利用 CPU 多核运算的优势。我们一般情况下说的线程其实是指用户线程;

内核级线程

内核线程由操作系统管理和调度,能够直接操作计算机底层的资源,线程切换的时候 CPU 需要切换到内核态。它能够很好利用多核 CPU 并行计算的优势,开发人员可以通过系统调用使用内核线程。

两级线程

两级线程模型相当于用户级线程和内核级线程的结合,一个进程将会对应多个内核线程,由进程内的调度器决定进程内的线程如何与申请的内核线程对应。

MPG(machine processor goroutine)模型

MPG 线程模型对两级线程模型进行一定程度的改进

  • machine:一个 machine 对应一个内核线程,相当于内核线程在 Golang 进程中的映射
  • processor:一个 prcessor 表示执行 Go 代码片段的所必需的上下文环境,可以理解为用户代码逻辑的处理器
  • goroutine:是对 Golang 中代码片段的封装,其实是一种轻量级的用户线程。

Go语言中切片的默认长度和容量是多少?

s00 := make([]int, 0)
fmt.Println(len(s00))
fmt.Println(cap(s00))
var s01 []int
fmt.Println(len(s01))
fmt.Println(cap(s01))
// 使用:=创建切片
s1 := []int{1, 2, 3}
fmt.Println(len(s1))
fmt.Println(cap(s1))
// 使用make创建切片
var s2 = make([]int, 3)
fmt.Println(len(s2))
fmt.Println(cap(s2))

var s3 = make([]int, 3, 5)
fmt.Println(len(s3))
fmt.Println(cap(s3))
// 切片扩容
var s4 = make([]int, 3, 5)
fmt.Println(len(s4))
fmt.Println(cap(s4))
s4 = append(s4, 1,2,3,4,5,6)
fmt.Println(len(s4))
fmt.Println(cap(s4))

在Gorm中,string和*string的区别是什么?

  • string是字符串类型,*string是字符串指针类型。
  • 当其对应的变量为空时,string类型存入数据库的为空字符串,*string类型存入数据库的为nil(null)。

Go语言打包部署

go build [-o output] [-i] [build flags] [packages]

-o:指定输出目录与打包后的文件名,代替默认的包名。

-i:安装作为目标的依赖关系的包(用于增量编译提速)

Windows平台

set GOARCH=amd64
set GOOS=windows
go build main.go

Linux平台

set GOARCH=amd64
set GOOS=linux
go build main.go

GOOS:目标操作系统

  • darwin
  • freebsd
  • linux
  • windows
  • android
  • dragonfly
  • netbsd
  • openbsd
  • plan9
  • solaris

GOARCH:目标处理器的架构

  • arm
  • arm64
  • 386
  • amd64
  • ppc64
  • ppc64le
  • mips64
  • mips64le
  • s390x

数据库

简述悲观锁和乐观锁

悲观锁

总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。

乐观锁

总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。

数据库范式

  • 第一范式(1NF):数据库表的每一列都是不可分割的原子数据项,而不能是集合,数组,记录等非原子数据项。
  • 第二范式(2NF):要求数据库表中的每个实例或记录必须可以被唯一地区分。
  • 第三范式(3NF):要求一个关系中不包含已在其它关系已包含的非主关键字信息。
  • 巴斯-科德范式(BCNF):任何非主属性不能对主键子集依赖。
  • 第四范式(4NF)
  • 第五范式(5NF,又称完美范式)

数据库优化

  • 添加索引
  • 读写分离
  • 字段冗余
  • 分库分表

算法

简述常见排序算法的时间复杂度及最好情况

算法名称平均时间复杂度最坏时间复杂度最好时间复杂度空间复杂度稳定性备注
选择排序 n 2 n^2 n2 n 2 n^2 n2 n 2 n^2 n2 1 1 1不稳定
冒泡排序 n 2 n^2 n2 n 2 n^2 n2 n n n 1 1 1稳定
插入排序 n 2 n^2 n2 n 2 n^2 n2 n n n 1 1 1稳定
堆排序 n l o g 2 n nlog_2n nlog2​n n l o g 2 n nlog_2n nlog2​n n l o g 2 n nlog_2n nlog2​n 1 1 1不稳定
希尔排序 n 1.3 n^{1.3} n1.3 n 2 n^2 n2 n n n 1 1 1不稳定
归并排序 n l o g 2 n nlog_2n nlog2​n n l o g 2 n nlog_2n nlog2​n n l o g 2 n nlog_2n nlog2​n n n n稳定
快速排序 n l o g 2 n nlog_2n nlog2​n n 2 n^2 n2 n l o g 2 n nlog_2n nlog2​n n l o g 2 n nlog_2n nlog2​n不稳定
桶排序 n + k n+k n+k n 2 n^2 n2 n n n n + k n+k n+k稳定
计数排序 n + k n+k n+k n + k n+k n+k n + k n+k n+k n + k n+k n+k稳定
基数排序 n ∗ k n*k n∗k n ∗ k n*k n∗k n ∗ k n*k n∗k n + k n+k n+k稳定

从有序的1000个数中找到一个数的伪代码

法一:

  1. 以100为粒度寻找对应得百区间
  2. 以10为粒度寻找对应得十区间
  3. 以1为粒度寻找对应得个区间

法二:

二分查找

网络

简述TCP和UDP的区别

UDPTCP
是否连接无连接面向连接
是否可靠不可靠连接,不使用流量控制和拥塞控制可靠连接,使用流量控制和拥塞控制
连接对象个数支持一对一、一对多、多对一和多对多交互通信只能一对一通信
传输方式面向报文面向字节流
首部开销首部开销小,仅8字节首部开销最小20字节、最大60字节
适用场景适用实时应用(IP电话、视频会议、直播)适用于要求可靠传输的应用,如文件传输

其他

为什么高考成绩这么低?(学霸请忽略)

这是个挖坑的问题!!!

只能说自己没努力,任何客观的解释都无效!

当项目进度明显完不成,作为Leader你应该怎么办?

加班!!!

参考文档

https://www.cnblogs.com/HinaChan/p/14842521.html#

https://cloud.tencent.com/developer/article/1444356

https://www.topgoer.com/go%E5%9F%BA%E7%A1%80/%E5%9F%BA%E6%9C%AC%E7%B1%BB%E5%9E%8B.html

http://dockone.io/article/10491
https://blog.csdn.net/qq_40694036/article/details/101170698