专业的编程技术博客社区

网站首页 > 博客文章 正文

【Go语言】Golang中原子操作用法(go 原子操作)

baijin 2024-09-26 06:59:38 博客文章 3 ℃ 0 评论

在Go语言中,原子操作可以用来保证并发安全,避免竞争条件。Go语言中提供了sync/atomic标准库来支持原子操作。下面是一些常见的原子操作的示例。

原子加

package main

import (
	"fmt"
	"sync"
	"sync/atomic"
)

func main() {
	var count int32

	var wg sync.WaitGroup
	wg.Add(100)

	for i := 0; i < 100; i++ {
		go func() {
			atomic.AddInt32(&count, 1)
			wg.Done()
		}()
	}

	wg.Wait()

	fmt.Println("Count:", count)
}

在这个例子中,我们创建了一个int32类型的变量count,然后启动了100个goroutine,每个goroutine执行一次原子加操作atomic.AddInt32(&count, 1)。最终输出count的值,可以看到结果是100,说明原子加操作是并发安全的。

原子比较并交换

package main

import (
	"fmt"
	"sync"
	"sync/atomic"
)

func main() {
	var count int32

	var wg sync.WaitGroup
	wg.Add(100)

	for i := 0; i < 100; i++ {
		go func() {
			old := count
			for !atomic.CompareAndSwapInt32(&count, old, old+1) {
				old = count
			}
			wg.Done()
		}()
	}

	wg.Wait()

	fmt.Println("Count:", count)
}

在这个例子中,我们同样创建了一个int32类型的变量count,然后启动了100个goroutine,每个goroutine执行一次原子比较并交换操作atomic.CompareAndSwapInt32(&count, old, old+1)。在这个操作中,首先获取当前count的值,并将其保存在old变量中,然后调用atomic.CompareAndSwapInt32()方法,如果count的值等于old,则将count的值更新为old+1,否则不更新。如果更新失败,则重新获取count的值,继续执行比较并交换操作。最终输出count的值,可以看到结果是100,说明原子比较并交换操作也是并发安全的。

原子加载和存储

package main

import (
	"fmt"
	"sync"
	"sync/atomic"
)

func main() {
	var count int32

	var wg sync.WaitGroup
	wg.Add(2)

	go func() {
		for {
			val := atomic.LoadInt32(&count)
			fmt.Println("Read count:", val)
			if val >= 10 {
				wg.Done()
				return
			}
		}
	}()

	go func() {
		for i := 0; i < 10; i++ {
			atomic.StoreInt32(&count, int32(i))
			fmt.Println("Write count:", i)
		}
		wg.Done()
	}()

	wg.Wait()

	fmt.Println("Done")
}

在这个例子中,我们创建了一个int32类型的变量count,然后启动了两个goroutine。第一个goroutine不断地读取count的值,如果count的值大于等于10,则退出循环。第二个goroutine执行10次原子存储操作atomic.StoreInt32(&count, int32(i)),将count的值更新为0到9之间的整数。最终输出Done,说明程序正常结束。

以上是一些常见的原子操作的示例,这些操作可以用来保证并发安全,避免竞争条件。需要注意的是,使用原子操作并不意味着程序就是正确的,还需要注意竞争条件的发生时机和条件。

原子操作和加锁的区别

原子操作和加锁都是保证并发安全的机制,但它们有一些不同的特点和应用场景。

  • 原子操作

原子操作是一种非常轻量级的同步机制,它是基于硬件层面的支持,能够保证单个操作的原子性,不需要像加锁那样进行上下文切换和操作系统调度,因此具有非常高的性能。原子操作适用于处理简单的数据结构,例如整型、指针等,能够保证数据的一致性和可见性,但是无法处理复杂的数据结构,例如链表、哈希表等。

  • 加锁

加锁是一种更加通用的同步机制,它能够保证在同一时刻只有一个goroutine可以访问共享资源,从而避免竞争条件。加锁的实现通常需要进行上下文切换和操作系统调度,因此相对于原子操作,性能较低。加锁适用于处理复杂的数据结构和共享资源,例如链表、哈希表等。

另外,需要注意的是,使用原子操作并不能完全替代加锁,因为在一些情况下需要对多个变量进行操作,并且保证这些操作的原子性和可见性,这时候就需要使用加锁。在实际应用中,需要根据具体的场景和需求来选择使用原子操作还是加锁。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表