go中数组、切片、map是否线程(并发)安全?

这篇具有很好参考价值的文章主要介绍了go中数组、切片、map是否线程(并发)安全?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

博客主页:🏆看看是李XX还是李歘歘 🏆

🌺每天不定期分享一些包括但不限于计算机基础、算法、后端开发相关的知识点,以及职场小菜鸡的生活。🌺

💗点关注不迷路,总有一些📖知识点📖是你想要的💗 

目录

什么是线程(并发)安全?

非线程安全原因

map

解决方案

数组

解决方案

切片

解决方案

Go其他数据类型的并发安全性


先给出结论:在Go中数组、切片和map都是非线程安全的。

什么是线程(并发)安全?

线程(并发)安全是指程序在并发执行或者多个线程同时操作的情况下,执行结果还是正确的。

非线程安全原因

map

Go语言中的 map 在并发情况下,只读是线程安全的,同时读写是线程不安全的。同一个变量在多个goroutine中访问需要保证其安全性

因为map变量为指针类型变量,并发写时,多个协程同时操作一个内存,类似于多线程操作同一个资源会发生竞争关系,共享资源会遭到破坏,因此golang出于安全的考虑,抛出致命错误:fatal error: concurrent map writes

 非并发安全map(普通的map)

package main

import (
	"fmt"
	"strconv"
	"sync"
)

var m = make(map[string]int)

func get(key string) int {
	return m[key]
}

func set(key string, value int) {
	m[key] = value
}

func main() {
	wg := sync.WaitGroup{}
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func(n int) {
			key := strconv.Itoa(n)
			set(key, n)
			fmt.Printf("k=:%v,v:=%v\n", key, get(key))
			wg.Done()
		}(i)
	}
	wg.Wait()
}

解决方案

(1)在写操作的时候增加锁

package main

import (
	"fmt"
	"sync"
)

func main() {
	var lock sync.Mutex
	var maplist map[string]int
	maplist = map[string]int{"one": 1, "two": 2}
	lock.Lock()
	maplist["three"] = 3
	lock.Unlock()
	fmt.Println(maplist)
}

(2)sync.Map包

package main

import (
	"fmt"
	"sync"
)

func main() {
	m := sync.Map{} //或者 var mm sync.Map
	m.Store("a", 1)
	m.Store("b", 2)
	m.Store("c", 3)                             //插入数据
	fmt.Println(m.Load("a"))                    //读取数据
	m.Range(func(key, value interface{}) bool { //遍历
		fmt.Println(key, value)
		return true
	})
}

数组

指定索引进行读写时,数组是支持并发读写索引区的数据的,但是索引区的数据在并发时会被覆盖的;

解决方案

1.加锁

2.控制并发顺序

切片

指定索引进行读写:是支持并发读写索引区的数据的,但是索引区的数据在并发时可能会被覆盖的;

发生切片动态扩容:并发场景下扩容可能会被覆盖。

切片是对数组的抽象,其底层就是数组,在并发下写数据到相同的索引位会被覆盖,并且切片也有自动扩容的功能,当切片要进行扩容时,就要替换底层的数组,在切换底层数组时,多个goroutine是同时运行的,哪个goroutine先运行是不确定的,不论哪个goroutine先写入内存,肯定就有一次写入会覆盖之前的写入,所以在动态扩容时并发写入数组是不安全的;

解决方案

1.加互斥锁
2.使用channel串行化操作
3.使用sync.map代替切片(github上著名的iris框架也曾遇到过切片动态扩容导致webscoket连接数减少的bug,最终采用sync.map解决了该问题, 采用sync.map解决切片并发安全)

Go其他数据类型的并发安全性

数据类型参考:

Go 中所有类型并发赋值的安全性。

(1)由一条机器指令完成赋值的类型并发赋值是安全的,这些类型有:字节型,布尔型、整型、浮点型、字符型、指针、函数。

(2)数组由一个或多个元素组成,大部分情况并发不安全。注意:当位宽不大于 64 位且是 2 的整数次幂(8,16,32,64),那么其并发赋值是安全的。

(3)struct 或底层是 struct 的类型并发赋值大部分情况并发不安全,这些类型有:复数、字符串、 数组、切片、映射、通道、接口。注意:当 struct 赋值时退化为单个字段由一个机器指令完成赋值时,并发赋值又是安全的。这种情况有:
(a)实部或虚部相同的复数的并发赋值;
(b)等长字符串的并发赋值;
(c)同长度同容量切片的并发赋值;
(d)同一种具体类型不同值并发赋给接口。
————————————————
版权声明:本文为CSDN博主「恋喵大鲤鱼」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/K346K346/article/details/115099353

这篇文章写的很好,感谢博主,但是底层是 struct 的类型的channel是并发安全的,还有待博主回复

参考:

(43条消息) 【golang学习笔记】Go语言中参数的传递是值传递还是引用传递_Vivien_oO0的博客-CSDN博客_golang 切片是值传递还是引用传递

(43条消息) Go并发安全sync.Map_JIeJaitt的博客-CSDN博客

(43条消息) golang-数组,切片,map是否线程安全?_golang 切片线程安全_一颗简单的心的博客-CSDN博客 (43条消息) Go语言map使用和并发安全_行走的皮卡丘的博客-CSDN博客_go map并发安全

(43条消息) GoLang之切片并发安全问题_GoGo在努力的博客-CSDN博客_golang 切片线程安全文章来源地址https://www.toymoban.com/news/detail-434773.html

到了这里,关于go中数组、切片、map是否线程(并发)安全?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Go语言快速上手(三)】数组, 切片与映射

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:Go语言专栏⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习更多Go语言知识   🔝🔝 在了解过GO的控制语句和函数后,按照学习语言的逻辑也理应进入到容器的学习,GO语言的容易比较特殊,它不像C++一样有专门的STL库

    2024年04月29日
    浏览(41)
  • Go语言中的数组、切片和映射解析

    数组存放的是固定长度、相同类型的数据,而且这些存放的元素是连续的。 例如声明一个整形数组: 在类型名前加 [] 中括号,并设置好长度,大括号中的元素用于初始化数组,需要注意的是数组的长度不同,即属于不同的类型。 如果所有元素都被初始化的数组,声明时可以

    2024年02月09日
    浏览(36)
  • Go 语言为什么建议多使用切片,少使用数组?

    大家好,我是 frank,「Golang 语言开发栈」公众号作者。 01 介绍 在 Go 语言中,数组固定长度,切片可变长度;数组和切片都是值传递,因为切片传递的是指针,所以切片也被称为“引用传递”。 读者朋友们在使用 Go 语言开发项目时,或者在阅读 Go 开源项目源码时,发现很少

    2024年02月03日
    浏览(49)
  • 【Golang】Golang进阶系列教程--Go 语言数组和切片的区别

    在 Go 语言中,数组和切片看起来很像,但其实它们又有很多的不同之处,这篇文章就来说说它们到底有哪些不同。 数组和切片是两个常用的数据结构。它们都可以用于存储一组相同类型的元素,但在底层实现和使用方式上存在一些重要的区别。 Go 中数组的长度是不可改变的

    2024年02月15日
    浏览(43)
  • Go 语言为什么不支持并发读写 map?

    大家好,我是 frank ,「 Golang 语言开发栈」公众号作者。 01 介绍 在 Go 语言项目开发中,我们经常会使用哈希表 map ,它的时间复杂度是 O(1) ,Go 语言中的 map 使用开放寻址法避免哈希碰撞。 Go 语言中的 map 并非原子操作,不支持并发读写操作。 Go 官方认为 map 在大多数情况下

    2024年02月02日
    浏览(42)
  • 使用go_concurrent_map 管理 并发更新缓存

    在后台服务中,为了提速,我在内存还做了一个告诉缓存来管理用户信息,根据更新通知,或者定时去redis中同步信息,那么在加载或者更新某个用户元素时,要防止并发, 当: 1)如果内存缓存没有; 2)去数据库或者redis加载; 3)添加到内存缓存; 这里就有个并发重复的

    2024年04月25日
    浏览(25)
  • Go 自学:map关联数组

    以下代码展示了如何建立一个map。 我们可以使用delete删除map中的元素。 我们还可以使用loop遍历map中的所有元素。 输出为: List of all languages: map[JS:Javascript PY:Python RB:Ruby] JS shorts for: Javascript List of all languages: map[JS:Javascript PY:Python] For key JS, value is Javascript For key PY, value is Pytho

    2024年02月11日
    浏览(23)
  • 你是否想知道如何应对高并发?Go语言为你提供了答案!

    并发编程是当前软件领域中不可忽视的一个关键概念。随着CPU等硬件的不断发展,我们都渴望让我们的程序运行速度更快、更快。而Go语言在语言层面天生支持并发,充分利用现代CPU的多核优势,这也是Go语言能够广泛流行的一个重要原因。 在Java中,要支持高并发有几种方案

    2024年02月04日
    浏览(33)
  • 慕课网Go-2.数组、slice、map、list

    2024年02月15日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包