無名

大猫咪与小狮子

导航

关于golang线程安全

 

golang中的string赋值是线程安全的吗?

第一反应,golang的string底层结构:

type stringStruct struct {
    str unsafe.Pointer
    len int
}

其中 str 是一个不变数组,
现在看来,针对这个问题,需要清楚:

  1. 我们所说的线程安全,是指操作,而不是指数据类型
  2. 假如某个操作在执行时,可以通过一条机器指令完成,那么它一定是线程安全的,因为这一条指令是一个原子操作
  3. 不可改变的数据与线程安全并没有关系,线程安全关注的是操作的安全性

比如,我们对某个变量的读操作,那么它一定是线程安全的,不管是map、sync.map、string、int,这个读操作都是线程安全的。

假如我们对一个 var int i = 10 做自增操作 i++,那么,这个操作就不是并发安全的,因为i++ 在机器指令上可以分为:读取i的值,对i的值做加1操作,这两个操作之间,很明显,会被中断,在多个线程操作的时候,会产生非预期的结果。

所以,面试题中的提问是指golang 中的string类型做 “赋值” 这个操作的时候,是线程安全的吗?

我们先抛开这个问题,考虑一个通用的场景,结构体类型的赋值是线程安全的吗?

比如一个结构体:

type S struct {
	b int
	a int
}
var v = S{a:1,b:2}
v = S{a:3,b:4}

上面中对变量中v的赋值操作,可分为对字段a的赋值,然后再对b的赋值,这是两个机器指令,所以,如果在两个并发的线程中操作,并不是线程安全的,那么,当结构体中只有一个字段,是否是线程安全的呢?答案是:线程安全的。

同样,假如你只修改结构体中的一个字段,其也是线程安全的,比如你只修改上面的结构体中的a字段,那么是线程安全的。

所以,同样的,对string的 赋值操作,也不是线程安全的,它与string的底层数组是否是不变数组没有关系。

延伸一下,那哪些类型在golang中赋值是线程安全的呢:

字节型、布尔型、整型、浮点型、字符型

以上这些类型的赋值都可以在一条机器指令完成,这儿特别说明一下,以int64位而言,如果在32位的机器上赋值,那么一条指令并不能完成,所以也是不安全的。

另外,指针类型,函数类型的赋值也是线程安全的。

以下类型的赋值不是线程安全的:

数组、切片、字典、通道、接口、sync.map、字符串、复数型的类型的赋值都不是线程安全的

 

posted on 2023-04-26 12:56  xiezhengcai  阅读(665)  评论(0编辑  收藏  举报