MST

星途 面试题库

面试题:Go字符串操作在并发场景下的优化与陷阱

在并发环境中,经常会涉及到对字符串的操作,比如多个协程同时读取和修改字符串内容。请详细说明在这种场景下可能会遇到的问题,以及如何通过合理的设计和使用Go语言的特性(如互斥锁、通道等)来优化和避免这些问题,并且提供一个简单的示例代码。
26.2万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

可能遇到的问题

  1. 数据竞争(Race Condition):多个协程同时读写字符串,可能导致数据不一致。比如一个协程读取字符串时,另一个协程正在修改它,使得读取到的内容不完整或错误。
  2. 内存损坏:如果多个协程无保护地同时修改字符串内容,可能导致内存中字符串的表示被破坏,引发程序崩溃。

解决方案

  1. 互斥锁(Mutex):使用sync.Mutex来保护对字符串的操作。在读取或修改字符串之前,先获取锁,操作完成后释放锁。这样同一时间只有一个协程能访问字符串,避免数据竞争。
  2. 通道(Channel):通过通道来传递字符串操作的请求,由一个专门的协程负责处理这些请求,从而避免多个协程直接操作字符串带来的竞争问题。

示例代码(使用互斥锁)

package main

import (
    "fmt"
    "sync"
)

var (
    str     string
    mu      sync.Mutex
    wg      sync.WaitGroup
)

func modifyString(newStr string) {
    defer wg.Done()
    mu.Lock()
    str = newStr
    mu.Unlock()
}

func readString() {
    defer wg.Done()
    mu.Lock()
    fmt.Println("Read string:", str)
    mu.Unlock()
}

func main() {
    str = "initial"
    wg.Add(2)

    go modifyString("new value")
    go readString()

    wg.Wait()
}

示例代码(使用通道)

package main

import (
    "fmt"
    "sync"
)

type StringOp struct {
    op    string
    value string
    reply chan string
}

func stringOperator(ch <-chan StringOp) {
    var str string
    for op := range ch {
        switch op.op {
        case "modify":
            str = op.value
            op.reply <- "Modified"
        case "read":
            op.reply <- str
        }
    }
}

func main() {
    var wg sync.WaitGroup
    ch := make(chan StringOp)
    go stringOperator(ch)

    // 修改字符串
    wg.Add(1)
    reply := make(chan string)
    ch <- StringOp{op: "modify", value: "new value", reply: reply}
    go func() {
        defer wg.Done()
        fmt.Println(<-reply)
    }()

    // 读取字符串
    wg.Add(1)
    reply2 := make(chan string)
    ch <- StringOp{op: "read", reply: reply2}
    go func() {
        defer wg.Done()
        fmt.Println("Read string:", <-reply2)
    }()

    close(ch)
    wg.Wait()
}