我想知道Go中的哪些数据类型本质上是线程安全的(如果有的话)。
我的假设是int,floats和bools是安全的,而复合类型则不是。
谢谢。
答案 0 :(得分:5)
我不相信他们中的任何一个都是保证是原子的,但有些可能是在实践中(当然,通过原子,我们的意思是分配到它们同时来自两个线程将产生一个或另一个值,而不是一些第三个值(例如每个值的位组合) - 我们并不意味着你可以原子地比较和商店或类似的东西)。最好的办法是查看Go Memory Model。
答案 1 :(得分:2)
请注意:
如果在编译它的同一平台上运行代码,则对单个字值进行变换通常应该是原子的。但是还有更多的东西使得必须使用原子指令(如果你不打算使用更强的保证)。
原因是除了编译器级别的内存重新排序之外,您可能在CPU级别进行了重新排序以进行优化。 (写入不会立即传播到主存储器,CPU有存储缓冲区等)。
因此,在多线程环境中,您需要明确地对所有内核显示更改,否则您将损坏内存。
就改变复合类型而言,是的,你需要(非常)小心。最简单的方法是锁定整个对象(嵌入互斥锁是一种很好的方法,它更加缓存友好)。
否则,如果您想以原子方式执行此操作,则可以采用读取 - 复制 - 更新方法(查找RCU或写入时复制),但请注意!除非你真的知道自己在做什么,否则你很容易陷入困境。如果将可变对象嵌套到其他可变对象中(查找有关嵌套无锁数据结构的可线性化的问题),那么很难做到这一点。这真的很棘手,我劝阻它。即使您要添加额外的间接级别以使您的数据结构看起来不可变,解决并发原子读取,更新和删除的问题也是博士级别的东西。如果你很好奇,请查找Aleksandar Prokopec的论文和论文:http://axel22.github.io/home/professional/
这就是渠道和互斥体为您服务的原因。而且我希望通道在已经很好的性能上有所提升。现在通道对于一些人来说很容易,但是我花了几天时间才能真正地绕过它们。但是一旦完成,使用起来非常简单。