面试题答案
一键面试数组与切片在高并发共享数据场景下的优缺点分析
- 数组
- 优点:
- 数组的长度是固定的,在编译时就确定,内存布局连续,对于固定大小的数据集合,使用数组访问效率较高,因为可以通过简单的偏移量快速定位元素。例如在一些固定长度的配置数据存储场景下,数组能高效存储和访问。
- 缺点:
- 长度固定,一旦声明大小不能改变。在高并发且数据量动态变化的场景下,数组灵活性不足。如果预估数据量不准确,可能导致空间浪费或者数据溢出。
- 优点:
- 切片
- 优点:
- 切片长度可变,能根据需求动态增长和收缩,非常适合数据量不确定的场景。例如在处理高并发的日志记录,随着日志不断产生,切片可以动态扩展存储。
- 切片是引用类型,在函数传递等操作时,开销较小,因为传递的是切片结构体(包含指向底层数组的指针、长度和容量),而不是整个数据副本。
- 缺点:
- 由于切片长度可变,其内存管理相对复杂,频繁的扩容操作可能带来性能开销。在高并发下,扩容操作可能会导致额外的资源竞争。
- 优点:
根据业务需求选择数组或切片
- 数据读写频率
- 读写频率低:如果数据读写频率较低且数据量固定,数组是较好的选择,因其固定长度和简单的内存布局能提供稳定的访问性能。例如,程序启动时读取一次配置数据并在后续少量使用,数组可有效存储配置数据。
- 读写频率高:当读写频率高且数据量动态变化时,切片更合适。如实时统计高并发请求的相关数据,随着请求不断到来,切片可动态扩展存储统计信息。
- 数据一致性要求
- 强一致性要求:对于数据一致性要求极高的场景,数组和切片都需要配合合适的同步机制。但数组相对简单的结构在使用同步机制时可能更容易理解和实现。例如银行账户余额等关键数据存储,使用数组并结合同步机制确保数据一致性。
- 弱一致性要求:在一些对一致性要求不那么严格的场景,如统计网站实时在线人数,切片的动态扩展性更能满足业务需求,通过适当的同步机制也能保证一定程度的数据正确性。
结合同步机制保证数据正确访问的代码示例
- 使用互斥锁(
sync.Mutex
)示例
package main
import (
"fmt"
"sync"
)
var (
mu sync.Mutex
slice []int
array [5]int
)
func writeSlice(wg *sync.WaitGroup) {
defer wg.Done()
mu.Lock()
slice = append(slice, 1)
mu.Unlock()
}
func writeArray(wg *sync.WaitGroup) {
defer wg.Done()
mu.Lock()
for i := range array {
array[i]++
}
mu.Unlock()
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go writeSlice(&wg)
}
for i := 0; i < 10; i++ {
wg.Add(1)
go writeArray(&wg)
}
wg.Wait()
fmt.Println("Slice:", slice)
fmt.Println("Array:", array)
}
在这个示例中,无论是对切片还是数组进行写操作,都通过互斥锁mu
来保证同一时间只有一个 goroutine 能进行写操作,从而保证数据的一致性。
2. 使用读写锁(sync.RWMutex
)示例
package main
import (
"fmt"
"sync"
)
var (
rwmu sync.RWMutex
slice []int
array [5]int
)
func readSlice(wg *sync.WaitGroup) {
defer wg.Done()
rwmu.RLock()
fmt.Println("Reading slice:", slice)
rwmu.RUnlock()
}
func writeSlice(wg *sync.WaitGroup) {
defer wg.Done()
rwmu.Lock()
slice = append(slice, 1)
rwmu.Unlock()
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go readSlice(&wg)
}
for i := 0; i < 5; i++ {
wg.Add(1)
go writeSlice(&wg)
}
wg.Wait()
}
这里使用读写锁rwmu
,读操作使用读锁RLock
,允许多个 goroutine 同时读;写操作使用写锁Lock
,保证写操作时其他 goroutine 不能读写,以此保证高并发下数据的正确访问。