1. Go语言中可以使用sync.WaitGroup来实现并发任务的同步

package main

import (
"fmt"
"sync"
) func hello(wg *sync.WaitGroup) {
defer wg.Done()
fmt.Println("hello")
} func main() {
var wg sync.WaitGroup
wg.Add(1)
//go hello(wg) // 注意:wg是一个结构体,传递的时候需要传递指针,此处传递的结构体,导致wg.Wait()一直等待,死锁
go hello(&wg) wg.Wait()
fmt.Println("main over")
}

  需要注意sync.WaitGroup是一个结构体,传递的时候要传递指针。

2. sync.Once

在编程的很多场景下我们需要确保某些操作在高并发的场景下只执行一次,例如只加载一次配置文件、只关闭一次通道等。

Go语言中的sync包中提供了一个针对只执行一次场景的解决方案–sync.Once。

sync.Once只有一个Do方法

package main

import (
"fmt"
"log"
"net"
"os"
"sync"
)

var printPid sync.Once

func main() {
listener, err := net.Listen("tcp", "127.0.0.1:18888")
if err != nil {
log.Fatalln(err)
return
}
defer listener.Close()

for {
// 注意:无论for循环遍历多少次,此处的Do方法只会执行一次
printPid.Do(func() {
fmt.Println("当前进程的ID是:", os.Getpid())
})

conn, err := listener.Accept()
if err != nil {
log.Fatalln("监听端口错误", err)
}

log.Println(conn.RemoteAddr(), "链接成功")
//go handleConn(conn) // 开启一个goroutine来处理新到来客户端链接
}
}

 sync.Once结构体内部包含了一个互斥锁和布尔值,互斥锁保证布尔值和数据的安全,而布尔值用来记录初始化是否完成,

  这样设计就能保证初始化操作的时候是并发安全的,并且初始化操作也不会被执行多次

 

3. sync.Map

  go语言中内置的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() {
// 内置的map不是并发安全的
wg := sync.WaitGroup{}
for i := 0; i < 5; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
key := strconv.Itoa(i)
set(key, i)
fmt.Printf("key:%v, value:%v\n", key, get(key))
}(i)
}
wg.Wait()
}

上面的代码开启少量几个goroutine的时候可能没什么问题,当并发多了之后执行上面的代码就会报fatal error: concurrent map writes错误。

像这种场景下就需要为map加锁来保证并发的安全性了,Go语言的sync包中提供了一个开箱即用的并发安全版map–sync.Map。开箱即用表示不用像内置的map一样使用make函数初始化就能直接使用。同时sync.Map内置了诸如Store、Load、LoadOrStore、Delete、Range等操作方法。

package main

import (
"fmt"
"strconv"
"sync"
) func main() {
// go语言的sync包提供了开箱即用的并发安全的map-sync.Map,
// 开箱即用表示不用向内置的map一样使用make函数来初始化就能直接使用
var (
m = sync.Map{}
wg sync.WaitGroup
) for i := 0; i < 20; i++ {
wg.Add(1)
go func(i int) {
key := strconv.Itoa(i)
m.Store(key, i) // map赋值
v, _ := m.Load(key)
fmt.Printf("key:%v, value:%v\n", key, v) defer wg.Done()
}(i)
} wg.Wait() }

  

golang中的sync的更多相关文章

  1. golang中并发sync和channel

    golang中实现并发非常简单,只需在需要并发的函数前面添加关键字"go",但是如何处理go并发机制中不同goroutine之间的同步与通信,golang 中提供了sync包和channel ...

  2. 【记录一个问题】golang中使用sync.Pool反而造成了负优化

    之前有这样的代码:从http收数据后,进行snappy解码: dst := make([]byte, 0, len(httpRequestData)*5) dst, err = snappy.Deco ...

  3. golang 中 sync包的 WaitGroup

    golang 中的 sync 包有一个很有用的功能,就是 WaitGroup 先说说 WaitGroup 的用途:它能够一直等到所有的 goroutine 执行完成,并且阻塞主线程的执行,直到所有的 ...

  4. golang中sync.RWMutex和sync.Mutex区别

    golang中sync包实现了两种锁Mutex (互斥锁)和RWMutex(读写锁),其中RWMutex是基于Mutex实现的,只读锁的实现使用类似引用计数器的功能. type Mutex     f ...

  5. golang 中 sync.Mutex 的实现

    mutex 的实现思想 mutex 主要有两个 method: Lock() 和 Unlock() Lock() 可以通过一个 CAS 操作来实现 func (m *Mutex) Lock() { f ...

  6. Golang中WaitGroup使用的一点坑

    Golang中WaitGroup使用的一点坑 Golang 中的 WaitGroup 一直是同步 goroutine 的推荐实践.自己用了两年多也没遇到过什么问题.直到一天午睡后,同事扔过来一段奇怪的 ...

  7. golang中Context的使用场景

    golang中Context的使用场景 context在Go1.7之后就进入标准库中了.它主要的用处如果用一句话来说,是在于控制goroutine的生命周期.当一个计算任务被goroutine承接了之 ...

  8. golang中锁mutex的实现

    golang中的锁是通过CAS原子操作实现的,Mutex结构如下: type Mutex struct {     state int32                     sema  uint ...

  9. 【协作式原创】查漏补缺之Golang中mutex源码实现(预备知识)

    预备知识 CAS机制 1. 是什么 参考附录3 CAS 是项乐观锁技术,当多个线程尝试使用 CAS 同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是 ...

随机推荐

  1. JAVA微信公众号网页开发——将接收的消息转发到微信自带的客服系统

    如果公众号处于开发模式,普通微信用户向公众号发消息时,微信服务器会先将消息POST到开发者填写的url上,无法直接推送给微信自带的客服功能.如果需要把用户推送的普通消息推送到客服功能中,就需要进行代码 ...

  2. 【LeetCode】977. Squares of a Sorted Array 解题报告(C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 排序 日期 题目地址:https://leetcod ...

  3. 【LeetCode】212. Word Search II 解题报告(C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 前缀树 日期 题目地址:https://leetco ...

  4. 1188 最大公约数之和 V2

    1188 最大公约数之和 V2 题目来源: UVA 基准时间限制:2 秒 空间限制:262144 KB  给出一个数N,输出小于等于N的所有数,两两之间的最大公约数之和.       相当于计算这段程 ...

  5. 【项目管理】《IT项目管理》Kathy Schwalbe 第2章 IT项目管理和IT背景

    1.对项目管理采取系统的观点有何意义?如何在项目管理中采用系统的观点? 意义:有效处理复杂的环境 采用系统方法,系统分析,系统管理.2.解释组织的四个框架.他们是如何帮助项目经理理解项目的组织环境的? ...

  6. ​​​​​​​《MYSQL高级查询与编程》综合机试试卷 - 云南农职美和易思

    题目:银行mysql数据库系统管理 目录 题目:银行mysql数据库系统管理 一.语言和环境 二.题目(100分): 功能需求: 要求: 三.提交方式 四.评分标准: 五.实现代码: 创建表结构: 插 ...

  7. SpringCloud创建Config模块

    1.说明 本文详细介绍Spring Cloud创建Config模块的方法, 基于已经创建好的Spring Cloud父工程, 请参考SpringCloud创建项目父工程, 创建Config模块这个子工 ...

  8. Log4j2进阶使用(Pattern Layout详细设置)

    1.进阶说明 通过配置Layout打印格式化的日志, Log4j2支持很多的Layouts: CSV GELF HTML JSON Pattern Serialized Syslog XML YAML ...

  9. RabbitMQ基础教程系列

    Ubuntu16.04下,erlang安装和rabbitmq安装步骤 Ubuntu16.04下,rabbimq集群搭建 C# .net 环境下使用rabbitmq消息队列 .net core使用rab ...

  10. 2048 双人创新小游戏【JavaFX-FXGL游戏框架】

    一个 uml 课程的大作业,项目要求设计并开发一款 2048 与某种游戏类型相结合的创新游戏.可以选择只建模或者既建模又实现,既然要做当然是选择实现啦(虽然没有接触过游戏...期末周的莽冲hhh,小组 ...