首页 > 编程语言 >go并发编程

go并发编程

时间:2024-02-03 11:33:10浏览次数:47  
标签:编程 goroutine sync var 并发 func go

go的GMP并发模型,让go天然支持高并发,先了解一下GMP模型吧

GMP G协程,M工作线程、P处理器,M必须持有P才可以执行G
P维护着一个协程G队列,P依次将G调度到M中运行
if M0中G0发生系统调用,M0将释放P,冗余的M1获取P,继续执行P队列中剩余的G。(只要P不空闲就充分利用了CPU)
G0系统调用结束后,如果有空闲的P,则获取P继续执行G0,否则将G0放入全局队列,M0进入缓存池睡眠。(全局队列中的G主要来自从系统调用中恢复的G)

下面介绍一下编程常用的同步(synchronize)原语

互斥锁 mutex rwmutex,要了解自旋锁和

Once

多用于实现单例模式

饿汉模式,一般是直接创建一个包级变量直接使用即可,注意既然是单例模式,就不能让他人随意创建,类型要是私有的,使用接口暴露方法,让外部获得私有变量

懒汉模式,在第一次使用时创建,这里需要注意并发安全,可以使用sync.Once来保证并发安全

type Singleton interface {
	Work() string
}

type singleton2 struct{}

func (s *singleton2) Work() string {
	return "singleton2 is working"
}

func newSingleton2() *singleton2 {
	return &singleton2{}
}

var (
	instance *singleton2
	once     sync.Once
)

// GetSingleton2 用于获取单例模式对象
func GetSingleton2() Singleton {
	once.Do(func() {
		instance = newSingleton2()
	})

	return instance
}

Pool

sync.Pool 是 Go 语言标准库中的一个并发安全的对象池,用于缓存和重用临时对象,以提高性能。通常用于减少内存分配和垃圾回收的开销。PS:一般将变量Put回Pool中,需要将变量重置

var studentPool = sync.Pool{
	New: func() any {
		return new(Student)
	},
}
func BenchmarkUnmarshalWithPool(b *testing.B) {
	for n := 0; n < b.N; n++ {
		stu := studentPool.Get().(*Student)
		json.Unmarshal(buf, stu)
		studentPool.Put(stu)
	}
}

Cond

Cond是条件变量,可以让一组goroutine等待某个条件的发生。当条件发生时,调用Broadcast或者Signal来通知所有等待的goroutine继续执行。
需要注意的是 sync.Cond 都要在构造的时候绑定一个 sync.Mutex。Wait() 和 Signal() 函数必须在锁保护下的临界区中执行。Wait()一般放在for循环中,因为可能会出现虚假唤醒

var mu = &sync.Mutex{}
var done = false

func read(name string, c *sync.Cond) {
	c.L.Lock()
	for !done {
		c.Wait()
	}
	log.Println(name, "reading")
	c.L.Unlock()
}

func write(name string, c *sync.Cond) {
	time.Sleep(1 * time.Second)
	c.L.Lock()
	done = true
	c.L.Unlock()
	log.Println(name, "writting finish")
	c.Broadcast()
}

func main() {
	cond := sync.NewCond(mu)
	go read("reader1", cond)
	go read("reader2", cond)
	go read("reader3", cond)
	write("writer", cond)

	time.Sleep(time.Second * 3)
}

Channel

WaitGroup

注意Wait后不能再Add,否则会panic
扩展:errgroup,可以捕获goroutine中的panic,只要有一个goroutine出错,就会取消所有的goroutine

atomic

原子操作,用于解决并发问题,比如计数器,锁等

func main() {
	// 定义一个共享的计数器,使用 int64 类型
	var counter int64

	// 使用 WaitGroup 来等待所有 goroutine 完成
	var wg sync.WaitGroup

	// 启动多个 goroutine 来增加计数器的值
	for i := 0; i < 5; i++ {
		wg.Add(1)
		go func() {
			// 在每个 goroutine 中原子地增加计数器的值
			for j := 0; j < 100000; j++ {
				atomic.AddInt64(&counter, 1)
			}
			wg.Done()
		}()
	}

	// 等待所有 goroutine 完成
	wg.Wait()

	// 输出最终的计数器值
	fmt.Println("Final Counter Value:", atomic.LoadInt64(&counter))
}

标签:编程,goroutine,sync,var,并发,func,go
From: https://www.cnblogs.com/cheng-sir/p/18004471

相关文章

  • 详解torch The “freeze_support()” line can be omitted if the programis not goin
    详解torchThe“freeze_support()”linecanbeomittediftheprogramisnotgoingtobefrozentoproduce在使用torch进行多进程编程时,我们可能会遇到一行代码freeze_support()。这行代码通常在Windows操作系统下使用,用于确保在运行多进程之前对Python解释器进行初始化。然......
  • 【Python进阶】并发编程方式
    并发编程方式有哪些?threading模块---线程asyncio模块---协程concurrent.futures模块---进程+线程(应用于异步调用)multiprocessing模块---进程进程、线程、协程?进程:运行起来的程序就是进程,是操作系统分配资源的最小单位。线程:线程是进程的组成部分,一个进程可以拥有多个线......
  • JAVA8 - 异步编程
    目录FutureFutureFuture接口在JAVA5中被引入,设计初衷式对将来某个时刻会发生的结果进行建模。它建模了一中异步计算,返回一个执行运算结果的引用,当运算结束后,这个引用被返回给调用方。在Future中触发那些潜在耗时的操作把调用线程解放出来,让它能继续执行其他有价值的工作,不再......
  • 2024-02-03:用go语言,你有 k 个背包。给你一个下标从 0 开始的整数数组 weights, 其中 we
    2024-02-03:用go语言,你有k个背包。给你一个下标从0开始的整数数组weights,其中weights[i]是第i个珠子的重量。同时给你整数k,请你按照如下规则将所有的珠子放进k个背包。没有背包是空的。如果第i个珠子和第j个珠子在同一个背包里,那么下标在i到j之间的所有珠......
  • 第五章:面向对象编程(基础)
    面向对象概述软件开发方法:面向过程和面向对象面向过程:关注点在实现功能的步骤上PO:ProcedureOriented。代表语言:C语言面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。例如开汽车:启动、踩离合、挂挡、松离合......
  • 跟着王洋老师学编程 - 1.8 打字母游戏
    案例简述在一个300*400的窗体上,有10个随机产生的字母向下落,在键盘上敲字母,如果对了就消掉,初始成绩为1000分,每敲对一个字母加10分,如果字母落到屏幕下方,或者敲错扣100分。我的思路-创建一个窗体-创建一个字母画布类——继承画布类Panel、编写构造方法以初始化数据,实现多线程......
  • Go RPC 库
    RPC(RemotePoresedureCall)是远程方法调用的缩写。Go的RPC库可以实现通过网络或者其他I/O方式远程调用对象的方法。服务器注册一个对象,让它作为一个以对象类型命名的服务,让这个对象导出的方法可以被远程调用。一个服务器可以注册多个不同类型的对象,但是不能注册同一类型的多个......
  • 数学概率拆分——cf_921_D.Good Trip
    目录问题概述思路想法参考代码问题反思问题概述原题参考:D.GoodTrip大致意思就是一个老师带着n个孩子,其中有m对是朋友,每对朋友之间有一个友谊值,不是朋友的则是0,这个老师要出去玩k次,每次可以带上两个小朋友(为什么不能一起带,这是偏爱!!!),如果这两个小朋友是朋友关系的话,那么他们的......
  • Golang 向已关闭的chan读写数据会怎样
    1.向已关闭的chan写会直接panic,报sendtoclosechannel错误packagemainfuncmain(){ //创建缓冲区为4的字符串chan schoolChan:=make(chanstring,4) //放入3个值 schoolChan<-"国防科大" schoolChan<-"北京大学" schoolChan<-"湖南大学" //......
  • Golang中make和new的区别
    1.相同点都是内建函数,都是在堆上分配内存,都需要传递类型参数2.不同点传递的参数不一样,new函数只接收一个参数,make函数可以接收一个以上的参数packagemainimport"fmt"funcmain(){ //int类型0值的指针,返回的值是以0x开头的16进制整数,参数个数为1 intZeroValueP......