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语言中的零值
类型 | 长度(字节) | 默认值(零值) | 说明 |
---|---|---|---|
bool | 1 | false | |
byte | 1 | 0 | uint8 |
rune | 4 | 0 | Unicode Code Point, int32 |
int, uint | 4或8 | 0 | 32 或 64 位 |
int8, uint8 | 1 | 0 | -128 ~ 127, 0 ~ 255,byte是uint8 的别名 |
int16, uint16 | 2 | 0 | -32768 ~ 32767, 0 ~ 65535 |
int32, uint32 | 4 | 0 | -21亿~ 21亿, 0 ~ 42亿,rune是int32 的别名 |
int64, uint64 | 8 | 0 | |
float32 | 4 | 0.0 | |
float64 | 8 | 0.0 | |
complex64 | 8 | ||
complex128 | 16 | ||
uintptr | 4或8 | 以存储指针的 uint32 或 uint64 整数 | |
array | 值类型 | ||
struct | 值类型 | ||
string | “” | UTF-8 字符串 | |
slice | nil | 引用类型 | |
map | nil | 引用类型 | |
channel | nil | 引用类型 | |
interface | nil | 接口 | |
function | nil | 函数 |
在Go语言中,Map是线程安全的吗?
sync.map
简述Go语言的GC(垃圾回收)机制
标记-清除(mark and sweep)算法(Go 1.3之前)
- 暂停程序业务逻辑,找出不可达对象,然后坐上标记并回收标记好的对象。
- 程序找出它所有可达的对象,并做上标记。
- 清除未标记的对象。
- 停止暂停,让程序继续跑。然后循环重复这个过程,直到process程序生命周期结束。
三色并发标记法(Go 1.5)
- 只要是新创建的对象,默认的颜色都是标记为“白色”;
- 每次GC回收开始,然后从根节点开始遍历所有对象,把遍历到的对象从白色集合放入“灰色”集合;
- 遍历灰色集合,将灰色对象引用的对象从白色集合放入灰色集合,之后将此灰色对象放入黑色集合;
- 重复第3步, 直到灰色中无任何对象;
- 回收所有的白色标记表的对象。
混合写屏障(hybrid write barrier)机制(Go 1.8)
-
GC开始将栈上的对象全部扫描并标记为黑色(之后不再进行第二次重复扫描,无需STW)。
-
GC期间,任何在栈上创建的新对象,均为黑色。
-
被删除的对象标记为灰色。
-
被添加的对象标记为灰色。
总结
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 nlog2n | n l o g 2 n nlog_2n nlog2n | n l o g 2 n nlog_2n nlog2n | 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 nlog2n | n l o g 2 n nlog_2n nlog2n | n l o g 2 n nlog_2n nlog2n | n n n | 稳定 | |
快速排序 | n l o g 2 n nlog_2n nlog2n | n 2 n^2 n2 | n l o g 2 n nlog_2n nlog2n | n l o g 2 n nlog_2n nlog2n | 不稳定 | |
桶排序 | 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个数中找到一个数的伪代码
法一:
- 以100为粒度寻找对应得百区间
- 以10为粒度寻找对应得十区间
- 以1为粒度寻找对应得个区间
法二:
二分查找
网络
简述TCP和UDP的区别
UDP | TCP | |
---|---|---|
是否连接 | 无连接 | 面向连接 |
是否可靠 | 不可靠连接,不使用流量控制和拥塞控制 | 可靠连接,使用流量控制和拥塞控制 |
连接对象个数 | 支持一对一、一对多、多对一和多对多交互通信 | 只能一对一通信 |
传输方式 | 面向报文 | 面向字节流 |
首部开销 | 首部开销小,仅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