FeelingLife FeelingLife
首页
  • Go

    • Go基础知识
  • Python

    • Python进阶
  • 操作系统
  • 计算机网络
  • MySQL
  • 学习笔记
  • 常用到的算法
  • Docker
  • Kubernetes
  • Observability
  • 容器底层
其他技术
  • 友情链接
  • 收藏
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

xuqil

一介帆夫
首页
  • Go

    • Go基础知识
  • Python

    • Python进阶
  • 操作系统
  • 计算机网络
  • MySQL
  • 学习笔记
  • 常用到的算法
  • Docker
  • Kubernetes
  • Observability
  • 容器底层
其他技术
  • 友情链接
  • 收藏
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 环境部署

  • 测试

  • 反射

  • 数据库操作

  • 并发编程

  • 内存管理

  • 线程安全

    • Go 的 string 是否线程安全
      • string的值是不可变的
      • string变量是可变的
      • string线程不安全
      • 参考
  • Go 技巧

  • middleware

  • 第三方库

  • Go各版本特性

  • 《go基础知识》
  • 线程安全
xuqil
2023-04-26
目录

Go 的 string 是否线程安全

# Go 的 string 是否线程安全

string是 Go 的内建类型,我们知道string的值是不可变的,但string变量不是。如果多个 goroutine 同时修改同一个string变量,需要添加线程安全机制,例如锁或者原子操作。

# string的值是不可变的

func TestModifyString(t *testing.T) {
	var s string = "abc"
	s[0] = '0' // Cannot assign to s[0]
}
1
2
3
4

执行这个测试得到的结果:

cannot assign to s[0] (value of type byte)
1

# string变量是可变的

func TestString2(t *testing.T) {
	a := "hello"
	a = "world"
	fmt.Println(a)
}
1
2
3
4
5

执行这个测试得到的结果:

world
1

# string线程不安全

string底层是一个struct类型,包含一个字符串描述符str和一个长度len。

runtime/string.go

type stringStruct struct {
    str unsafe.Pointer
    len int
}
1
2
3
4

下面这个测试可以检测string是否线程安全:

func TestString(t *testing.T) {
	ch := make(chan string)
	a := "1"
	go func() {
		i := 0
		for {
			if i%2 == 0 {
				a = "1"
			} else {
				a = "22"
			}
			time.Sleep(time.Millisecond * 1) // 阻止编译器优化
			i++
		}
	}()

	go func() {
		for {
			b := a
			if b != "1" && b != "22" {
				ch <- b
			}
		}
	}()

	for i := 0; i < 10; i++ {
		fmt.Println("Got string: ", <-ch)
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

执行这个测试得到的结果:

Got string:  2
Got string:  2
Got string:  15
Got string:  2
Got string:  2
Got string:  15
Got string:  15
Got string:  15
Got string:  2
Got string:  2
1
2
3
4
5
6
7
8
9
10

可以看到在频繁的写入操作中,另一协程可能读到部分写入的结果跟预想的不一致。(len为1,指针指向22,或者是len为2,指针指向了1)。

在并发场景下,string跟interface一样,都是需要使用atomic包来保证读写的原子性。

# 参考

https://stackoverflow.com/questions/51249918/immutability-of-string-and-concurrency

上次更新: 2024/05/29, 06:25:22
new 和 make 的区别
inset(集合)

← new 和 make 的区别 inset(集合)→

最近更新
01
VXLAN互通实验
05-13
02
VXLAN
05-13
03
VLAN
05-13
更多文章>
Theme by Vdoing | Copyright © 2018-2025 FeelingLife | 粤ICP备2022093535号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式