字符串和并发性的不变性 [英] Immutability of string and concurrency

查看:63
本文介绍了字符串和并发性的不变性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们应该在编写字符串上进行同步吗?因为字符串是不可变的,所以我们永远不会在两个不同线程的读写之间出现不一致的状态,对吧?

Should we synchronize on writing strings? Since string is immutable we will never get inconsistent state between write and read from the 2 different threads, right?

换句话说,为什么我们没有 atomic 作为字符串类型?

On other words, why we don't have atomic for string type?

推荐答案

string值是不可变的,但变量不是.变量是-顾名思义-变量,它们的值可以更改.

string values are immutable, but variables are not. Variables are–what their name say–variable, their values can be changed.

访问string值不需要同步,该值不能更改.如果将string值交给您,则该值(string的内容)将始终保持不变(包unsafe的使用不计在内).

You don't need synchronization for accessing a string value, that can't change. If a string value is handed to you, that (the content of the string) will always remain the same (usage of package unsafe does not count).

如果要从多个goroutine同时访问string类型的变量,并且至少其中一次访问是写操作(更改string变量的值的写操作),则需要同步.对于Go中任何类型的变量都是如此,string类型在任何方面都不是特殊的.

You need synchronization when you want to access a variable of string type from multiple goroutines concurrently, if at least one of the accesses is a write (a write that changes the value of the string variable). This is true for variables of any type in Go, the string type is not special in any way.

这实际上意味着什么?

如果您有一个接收string"hello"的函数,则可以确保string值无论如何都保持为"hello".因此,如果您不自行更改参数(例如,您未为其分配新值),它将始终保持string"hello".

If you have a function that receives a string value "hello", you can be sure the string value will stay "hello" no matter what. Consequently if you don't change the argument yourself (e.g. you don't assign a new value to it), it will always hold the string value "hello".

作为反例,如果您的函数接收切片值[]byte{1, 2, 3},则由于切片是可变的,因此您没有相同的保证.调用方还具有切片值(slice标头),否则它不能首先传递它.而且,如果调用者同时修改切片的 elements ,则由于它们共享相同的后备数组,因此传递给您的切片还将看到更改的数据……具有正确的同步;因为如果没有同步,这将是一场数据争夺(因此是未定义的行为).

As a counter-example, if your function receives a slice value []byte{1, 2, 3}, you don't have the same guarantee, because slices are mutable. The caller also has the slice value (the slice header), else it couldn't pass it in the first place. And if the caller modifies the elements of the slice concurrently, since they share the same backing array, the slice that was handed to you will also see the changed data... with proper synchronization; because without synchronization this would be a data race (and hence undefined behavior).

请参见以下示例:

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)
}

输出(在游乐场上尝试):

First  s = [1 2 3]
Second s = [100 2 3]

聚焦在sliceTest()上:它接收到一个切片,并将其打印出来.然后稍等(对并发的goroutine进行修改",然后等待此修改完成),然后再次打印它,并且它已更改,但sliceTest()本身并未对其进行修改.

Focus on sliceTest(): it receives a slice, and it prints it. Then waits a little (gives a "go" to a concurrent goroutine to modify it, and waits for this modification to complete), and prints it again, and it has changed, yet sliceTest() itself did not modify it.

现在,如果sliceTest()会收到一个string自变量,则不会发生这种情况.

Now if sliceTest() would receive a string argument instead, this could not happen.

查看相关的/可能的重复项:不变的字符串和指针地址

See related / possible duplicate: Immutable string and pointer address

这篇关于字符串和并发性的不变性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆