Rud*_*koŭ 8 string concurrency atomic immutability go
我们应该同步写字符串吗?由于字符串是不可变的,因此从2个不同的线程写入和读取之间永远不会出现不一致的状态,对吗?
换句话说,为什么我们没有字符串类型的原子?
icz*_*cza 10
string值是不可变的,但变量不是.变量是 - 他们的名字 - 变量,它们的值可以改变.
您不需要同步来访问string无法更改的值.如果一个string值交给你,那个(它的内容string)将始终保持不变(包的unsafe使用不计算).
如果要string同时从多个goroutine 访问类型的变量,如果至少有一个访问是写入(写入更改string变量的值),则需要同步.对于Go中的任何类型的变量都是如此,该string类型在任何方面都不是特殊的.
这在实践中意味着什么?
如果您有一个接收string值的函数"hello",那么无论如何都可以确保该string值保持"hello"不变.因此,如果您不自己更改参数(例如,您不为其分配新值),它将始终保持该string值"hello".
作为一个反例,如果你的函数收到一个切片值[]byte{1, 2, 3},你就没有相同的保证,因为切片是可变的.调用者也有切片值(切片头),否则它无法在第一时间传递它.如果调用者同时修改切片的元素,由于它们共享相同的后备数组,因此传递给您的切片也将看到已更改的数据...具有适当的同步; 因为没有同步,这将是一个数据竞争(因而是未定义的行为).
看这个例子:
var sig = make(chan int)
func main() {
s := []byte{1, 2, 3}
go func() {
<-sig
s[0] = 100
sig <- 0
}()
sliceTest(s)
}
func sliceTest(s []byte) {
fmt.Println("First s =", s)
sig <- 0 // send signal to modify now
<-sig // Wait for modification to complete
fmt.Println("Second s =", s)
}
Run Code Online (Sandbox Code Playgroud)
输出(在Go Playground上试试):
First s = [1 2 3]
Second s = [100 2 3]
Run Code Online (Sandbox Code Playgroud)
专注于sliceTest():它接收切片,然后打印出来.然后等待一点(给一个并行的goroutine"go"来修改它,并等待这个修改完成),然后重新打印它,它已经改变了,但sliceTest()它本身并没有修改它.
现在如果sliceTest()会收到一个string参数,这不可能发生.
请参阅相关/可能重复:不可变字符串和指针地址