【问题记录】Go并发读写string会导致Panic

背景

学过java的同学应该比较清楚,string型字符串是不可变字符串,如果对其进行写操作,会重新申请一片内存空间,然后新建一个string,因此java的string可以说是内存安全的。
而在go中,string作为基础数据类型,想当然的会认为string也是并发安全的,然而实际上并不是如此。

代码

概率型panic,可以多尝试几次

package main

import (
	"fmt"
	"time"
)

func main() {
	commonString := "init"
	go func() {
		for i := 0; i < 10000; i++ {
			s := commonString
			fmt.Printf("s is %s", s)
		}
	}()
	for {
		commonString = ""
		time.Sleep(10 * time.Nanosecond)
		commonString = "/test/test/test"
		time.Sleep(10 * time.Nanosecond)
	}
}

------------------运行结果---------------------

goroutine 6 [running]:
fmt.(*buffer).writeString(...)
        /usr/local/go/src/fmt/print.go:108
fmt.(*fmt).padString(0x14000068d08?, {0x0, 0xf})
        /usr/local/go/src/fmt/format.go:110 +0x22c
fmt.(*fmt).fmtS(0x14000068d98?, {0x0?, 0x14000068d68?})
        /usr/local/go/src/fmt/format.go:359 +0x40
fmt.(*pp).fmtString(0x0?, {0x0?, 0x14000068d98?}, 0xb3a248?)
        /usr/local/go/src/fmt/print.go:497 +0xe4
fmt.(*pp).printArg(0x14000090000, {0x100b6fe40?, 0x1400009a150}, 0x73)
        /usr/local/go/src/fmt/print.go:741 +0x234
fmt.(*pp).doPrintf(0x14000090000, {0x100b460ac, 0x7}, {0x14000068fb8?, 0x1, 0x1})
        /usr/local/go/src/fmt/print.go:1077 +0x2e4
fmt.Fprintf({0x100b81fa8, 0x1400000e018}, {0x100b460ac, 0x7}, {0x14000068fb8, 0x1, 0x1})
        /usr/local/go/src/fmt/print.go:224 +0x54
fmt.Printf(...)
        /usr/local/go/src/fmt/print.go:233
main.main.func1()
        /Users/bytedance/GolandProjects/awesomeProject/main.go:13 +0x7c
created by main.main
        /Users/bytedance/GolandProjects/awesomeProject/main.go:10 +0x80

原因分析

go中字符串的本质其实是个结构体,如下

type StringHeader struct {
        Data uintptr
        Len  int
}

而在赋值的过程中,go底层对于需要分别对两个值进行赋值,因此无法保证原子,也没有使用锁进做并发安全的保证。因此,当长度被修改,但是指针仍然为空时就会导致panic。所以在实际开发中,尽量避免对同一个字符串并发的频繁的做读写及赋值操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值