Go 并发:互斥体与通道的示例
Go 并发编程中的计数器同步:Mutex、缓冲通道和非缓冲通道
在 Go 语言中构建并发应用程序时,同步至关重要,以确保安全地访问共享数据。Mutex
和 Channel
是 Go 中用于同步的主要工具。
本文探讨了构建安全并发计数器的几种方法。虽然参考文章使用 Mutex
解决了这个问题,但我们还将探讨使用缓冲通道和非缓冲通道的替代方法。
问题描述
我们需要构建一个可以安全地并发使用的计数器。
计数器代码
package main type Counter struct { count int } func (c *Counter) Inc() { c.count++ } func (c *Counter) Value() int { return c.count }
为了确保代码的并发安全,让我们编写一些测试。
1. 使用 Mutex
Mutex
(互斥锁)是一种同步原语,它确保一次只有一个 goroutine 可以访问代码的关键部分。它提供了一种锁机制:当一个 goroutine 锁定 Mutex
时,其他试图锁定它的 goroutine 将被阻塞,直到 Mutex
被解锁。因此,当需要保护共享变量或资源免受竞争条件影响时,通常会使用它。
package main import ( "sync" "testing" ) func TestCounter(t *testing.T) { t.Run("using mutexes and wait groups", func(t *testing.T) { counter := Counter{} wantedCount := 1000 var wg sync.WaitGroup var mut sync.Mutex wg.Add(wantedCount) for i := 0; i < wantedCount; i++ { go func() { defer wg.Done() mut.Lock() counter.Inc() mut.Unlock() }() } wg.Wait() if counter.Value() != wantedCount { t.Errorf("got %d, want %d", counter.Value(), wantedCount) } }) }
代码使用了 sync.WaitGroup
来跟踪所有 goroutine 的完成情况,并使用 sync.Mutex
来防止多个 goroutine 同时访问共享计数器。
2. 使用缓冲通道
通道是 Go 允许 goroutine 安全通信的一种方式。它们能够在 goroutine 之间传输数据,并通过控制对所传递数据的访问来提供同步。
在本例中,我们将利用通道来阻塞 goroutine,并只允许一个 goroutine 访问共享数据。缓冲通道具有固定的容量,这意味着它们可以在阻塞发送方之前容纳预定义数量的元素。只有当缓冲区已满时,发送方才会被阻塞。
package main import ( "sync" "testing" ) func TestCounter(t *testing.T) { t.Run("using buffered channels and wait groups", func(t *testing.T) { counter := Counter{} wantedCount := 1000 var wg sync.WaitGroup wg.Add(wantedCount) ch := make(chan struct{}, 1) ch <- struct{}{} // 允许第一个 goroutine 开始 for i := 0; i < wantedCount; i++ { go func() { defer wg.Done() <-ch counter.Inc() ch <- struct{}{} }() } wg.Wait() if counter.Value() != wantedCount { t.Errorf("got %d, want %d", counter.Value(), wantedCount) } }) }
代码使用容量为 1 的缓冲通道,允许一次只有一个 goroutine 访问计数器。
3. 使用非缓冲通道
非缓冲通道没有缓冲区。它们会阻塞发送方,直到接收方准备好接收数据。这提供了严格的同步,其中数据一次一个地传递到 goroutine 之间。
package main import ( "sync" "testing" ) func TestCounter(t *testing.T) { t.Run("using unbuffered channels and wait groups", func(t *testing.T) { counter := Counter{} wantedCount := 1000 var wg sync.WaitGroup wg.Add(wantedCount) ch := make(chan struct{}) go func() { for i := 0; i < wantedCount; i++ { ch <- struct{}{} } close(ch) }() for range ch { counter.Inc() wg.Done() } if counter.Value() != wantedCount { t.Errorf("got %d, want %d", counter.Value(), wantedCount) } }) }
代码使用非缓冲通道,确保一次只有一个 goroutine 访问计数器。
4. 使用缓冲通道,不使用 WaitGroup
我们还可以使用缓冲通道而不使用 WaitGroup
,例如使用无限循环或另一个通道来跟踪 goroutine 的完成情况。
结论
本文探讨了在 Go 中构建安全并发计数器的不同方法。掌握这些工具以及何时使用它们是编写高效且安全的并发 Go 程序的关键。
参考资源
本文受《Learn Go with tests》中同步章节的启发。
希望本文对您有所帮助!
以上是Go 并发:互斥体与通道的示例的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

OpenSSL,作为广泛应用于安全通信的开源库,提供了加密算法、密钥和证书管理等功能。然而,其历史版本中存在一些已知安全漏洞,其中一些危害极大。本文将重点介绍Debian系统中OpenSSL的常见漏洞及应对措施。DebianOpenSSL已知漏洞:OpenSSL曾出现过多个严重漏洞,例如:心脏出血漏洞(CVE-2014-0160):该漏洞影响OpenSSL1.0.1至1.0.1f以及1.0.2至1.0.2beta版本。攻击者可利用此漏洞未经授权读取服务器上的敏感信息,包括加密密钥等。

后端学习路径:从前端转型到后端的探索之旅作为一名从前端开发转型的后端初学者,你已经有了nodejs的基础,...

在BeegoORM框架下,如何指定模型关联的数据库?许多Beego项目需要同时操作多个数据库。当使用Beego...

GoLand中自定义结构体标签不显示怎么办?在使用GoLand进行Go语言开发时,很多开发者会遇到自定义结构体标签在�...

Go语言中用于浮点数运算的库介绍在Go语言(也称为Golang)中,进行浮点数的加减乘除运算时,如何确保精度是�...

Go爬虫Colly中的Queue线程问题探讨在使用Go语言的Colly爬虫库时,开发者常常会遇到关于线程和请求队列的问题。�...

本文介绍如何在Debian系统上配置MongoDB实现自动扩容,主要步骤包括MongoDB副本集的设置和磁盘空间监控。一、MongoDB安装首先,确保已在Debian系统上安装MongoDB。使用以下命令安装:sudoaptupdatesudoaptinstall-ymongodb-org二、配置MongoDB副本集MongoDB副本集确保高可用性和数据冗余,是实现自动扩容的基础。启动MongoDB服务:sudosystemctlstartmongodsudosys

Go语言中使用RedisStream实现消息队列时类型转换问题在使用Go语言与Redis...
