Golang后端基础面试题
- [一. 基础面](#一. 基础面)
- [二. 项目面(简单提问)](#二. 项目面(简单提问))
简介:主要面向准备开始面试找实习的学生或应届生,整体比较简单,主要供了解面试的基本情况,其中所有题都是阿良面试的原题,不过答案是阿良自己总结的,可供借鉴。
一. 基础面
-
平常怎么学习 Go
学习 Go 语言可以通过以下方式:
官方文档:阅读 Go的官方文档 和 Go by Example。
书籍:阅读《The Go Programming Language》和《Go in Action》等书籍。
实践项目:实际编写一些小项目或工作中的任务,用Go来解决问题。
在线课程:参加如 Coursera、Udemy 上的 Go 语言课程。
社区和论坛:参加Go相关的在线社区(如 Golang中国 和 Reddit),和其他开发者交流。
此外自己也会写一些博客将自己的学习总结进行输出性学习
-
你了解切片吗?详细介绍一下?
切片(slice)是 Go 中的一种数据结构。他是对数组的包装,即切片本身是一个结构体,这个结构体有有几个重要的字段即:指向底层数组的指针、长度和容量。
(指向底层数组的指针:指向实际存储元素的数组的起始位置。
长度(length):当前切片所包含的元素数量。
容量(capacity):从切片的起始位置到底层数组末尾的元素数量。) (需要知道面试不问不说)这种设计使得切片在操作时非常高效,因为它允许基于同一个数组创建多个切片,不会因为切片操作而频繁地复制数组。他此外他在扩容和使用上也会有一些区别。
a. 扩容机制:当切片容量不足时,Go会新创建一个比当前切片容量更大的数组(通常新的容量是旧的2倍),然后将原数组中的元素复制到新数组中,再将切片的底层数组指针指向新数组。
切片是引用类型:因为切片结构包含一个指向底层数组的指针,以及切片的长度和容量信息。多个切片可以共享同一个底层数组,因此它是引用类型。
b. 使用上:go的切片是一个引用类型的,在切片作为一个函数的参数进行函数调用时,会将这个切片的指针进行复制,在函数中对切片进行修改会影响到原本的切片。而数组是一个值类型,当数组作为一个函数的参数进行调用时,是将整个数组进行复制的,在函数中对数组是原数组的副本,因此在函数内对数组进行操作是不会影响原本的数组的。
-
Go的slice和数组的区别
定义:数组是固定长度的数据结构,而切片是基于数组构建的动态数据结构。
长度和容量:数组的长度是固定的,而切片的长度和容量是可变的。
赋值和传递:数组的赋值和传递是值拷贝,而切片是引用拷贝。
性能:对于频繁需要改变长度的情况,使用切片更为灵活和高效。
-
slice扩容是怎么扩的,新建底层数组?
扩容时,Go 会:
创建一个新的、较大的底层数组。
将旧数组的数据复制到新数组中。
将切片的底层数组指针更新为新数组。
- Golang 里面的 map 了解过吗?
Golang 的 map 是哈希表实现的,无序的键值对集合。其主要特性有 O(1) 的插入和查找时间复杂度。语法比较简单,如 make(map[string]int) 创建一个字符串键和整数值的 map。
- 项目中并发 map?
在并发环境中使用 map 时,可以使用 sync.Map,它是 golang 标准库的并发安全 map 实现,或者手动使用互斥锁(mutex)进行保护。
- 介绍 Go 协程和 Channel 及常用场景
协程(Goroutines)
Go 的协程(goroutines)是轻量级的线程,可以通过 go 关键字启动。例子:
go func() {
fmt.Println("Hello from goroutine")
}()
通道(Channel)
通道是 goroutines 之间通讯的方式。可以通过 make(chan Type) 创建,使用 <- 操作符进行发送和接收。例子:
ch := make(chan int)
go func() {
ch <- 42
}()
fmt.Println(<-ch)
常用场景
并行任务处理。
任务调度。
goroutines 之间的数据共享与同步。
- 互斥锁,正常模式,饥饿模式?一句话形容。提高吞吐量。
互斥锁(Mutex):确保同一时间只有一个 goroutine 访问共享资源。
正常模式:默认模式,通过公平锁确保公平竞争。
饥饿模式:优先照顾等待时间长的 goroutine,以避免长期等待。
一句话形容:通过合适的锁模式和策略,提高系统并发吞吐量。
-
MongoDB 相对于 MySQL 的优势?
灵活的模式:MongoDB 是面向文档的 NoSQL 数据库,可以轻易处理各种格式的数据。
水平扩展:MongoDB 支持分片存储,更容易水平扩展。
嵌套文档结构:使得存储和查询嵌套结构数据更加方便。
高可用性:支持复制集,实现高可用性和自动故障转移。 (简单了解) -
MySQL 的索引结构是什么?
MySQL 的索引主要基于 B+ 树 实现,能够高效地支持范围查询和顺序访问。
-
B树和 B+树的区别?(简单介绍)
B树:每个节点既存储键也存储数据。
B+树:所有数据都存储在叶子节点,内部节点只存储键。叶子节点通过指针相连,支持顺序遍历。
-
MySQL 使用 B+树 相比于 B树 的优势在哪?
更高的查询效率:因为所有的数据都在叶子节点,内节点只存储键,使得树的阶数更高,深度更小。
顺序访问:叶子节点通过指针相连,非常适合范围查询。
更少的 I/O 操作:密集的叶子节点存储更多数据,减少了磁盘 I/O 次数。
-
MySQL 隔离级别?
MySQL 支持四种事务隔离级别:
读未提交(Read Uncommitted)。
读已提交(Read Committed)。
可重复读(Repeatable Read)。
序列化(Serializable)。
-
InnoDB 默认隔离级别?
InnoDB 存储引擎的默认隔离级别是 可重复读(Repeatable Read)。
二. 项目面(简单提问)
-
多设备登录一个账号(使用 JWT 解决)
为了实现多设备登录一个账号,我们可以使用 JWT(JSON Web Token)来进行身份认证,步骤如下:
用户登录时,服务器生成一个 JWT 并返回给客户端。
客户端保存 JWT(通常是在 local storage 或 cookies 中)。(回话管理)
后续请求时,客户端将 JWT 附加到 HTTP 头部发送到服务器。
服务器验证 JWT 的合法性,来识别用户身份。
服务器维护一个全局的 JWT 黑名单,当用户注销或更换设备时,将旧的 JWT 加入黑名单并拒绝其后续请求。
-
超卖(悲观锁/乐观锁/Redis/Go基础)(先简单了解)
超卖问题指在高并发环境下,库存被超量售出的现象。可以通过以下方式解决:
悲观锁:通过数据库锁定库存记录,确保操作的原子性。
乐观锁:使用版本号或时间戳机制,在更新时检查数据是否被其他事务修改。
Redis:通过 Redis 的原子性操作(如 INCR 和 DECR),确保库存操作的原子性。
Go基础:在代码层面使用互斥锁或通道,来保证并发安全。
-
遇到的问题
这是一个需要你根据实际情况回答的问题。一般可以包含技术难题、项目管理问题、团队合作问题等方面。
-
了解一些校园情况
这也是一个开放性问题,可以根据你的学习经历、校园生活、参与的社团活动或组织的相关经验进行分享。