MST

星途 面试题库

面试题:Go数组与切片在并发场景下的特性及应用

在并发编程的场景下,Go语言的数组和切片各自有哪些特性?如何根据这些特性在并发程序中合理地选择使用数组还是切片?请通过实际代码示例,展示如何避免在并发操作数组或切片时可能出现的数据竞争问题。
41.1万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

Go语言数组和切片在并发编程中的特性

  1. 数组特性
    • 固定长度:声明后长度不可变。例如var arr [5]int,该数组长度永远是5。
    • 值类型:数组作为参数传递时,传递的是整个数组的副本,而不是引用。
  2. 切片特性
    • 动态长度:可根据需要动态增长和收缩。例如slice := make([]int, 0, 10),初始长度为0,容量为10,后续可通过append函数增加元素。
    • 引用类型:切片作为参数传递时,传递的是切片的引用,对切片的修改会影响到原始切片。

如何选择使用数组还是切片

  1. 数组:当数据量固定且不需要动态变化时,可使用数组。例如,一个表示星期几的数组,一周永远是7天,不会变化。
  2. 切片:在大多数情况下,尤其是数据量不确定或需要动态变化时,应使用切片。例如,在网络编程中接收数据,数据量是不确定的,使用切片更合适。

避免并发操作数组或切片时的数据竞争问题示例

  1. 使用互斥锁(Mutex)
package main

import (
    "fmt"
    "sync"
)

var (
    mu    sync.Mutex
    slice = make([]int, 0)
)

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(n int) {
            defer wg.Done()
            mu.Lock()
            slice = append(slice, n)
            mu.Unlock()
        }(i)
    }
    wg.Wait()
    fmt.Println(slice)
}
  1. 使用通道(Channel)
package main

import (
    "fmt"
)

func main() {
    ch := make(chan int)
    var result []int
    go func() {
        for i := 0; i < 10; i++ {
            ch <- i
        }
        close(ch)
    }()
    for num := range ch {
        result = append(result, num)
    }
    fmt.Println(result)
}

在第一个示例中,通过sync.Mutex来保护对切片的并发访问,避免数据竞争。在第二个示例中,使用通道来安全地在并发环境中传递数据,从而避免对共享切片的直接并发访问导致的数据竞争。