Demystifying Go (Golang), Google’s Programming Language: Sync Package - RWMutex and Once

Demystifying Go (Golang), Google’s Programming Language: Sync Package - RWMutex and Once

Introduction

Welcome back to the world of the sync package! If you’ve already ventured into using Mutex, get ready to discover the next level of concurrency programming: the powerful RWMutex and the elegant Once. The RWMutex offers refined mutual exclusion, giving your application that extra performance boost, while Once is a sleek way to ensure something happens only once — yes, perfect for a controlled singleton. Let’s dive in, Gopher! An ocean of knowledge awaits.

RWMutex

The RWMutex is like the smarter, stronger sibling of Mutex. Not only does it offer Lock and Unlock functions like Mutex, but it also provides an option to lock for read-only operations, reducing deadlock risks and optimizing locks. With the RLock and RUnlock methods, you can lock a resource for reading only, enabling more efficient access for resources that don’t require writing. Pretty cool, right?

In the example below, we simulate a bank account with a balance, a function for making withdrawals (Debit), and another for checking the balance (GetBalance). In the main function, we create an account with an initial balance of 5000, launch a goroutine to print the balance every millisecond, and then fire up multiple goroutines to debit $1 until the balance reaches zero. Everything looks perfect, right? Well, not so fast.

This code is a prime target for concurrency issues. If we run it with the --race flag, we’ll see that we have a race condition, and it’s only a matter of time before inconsistencies pop up. Check the test in the image below.

To fix this, we’ll add a new attribute called rwm of type RWMutex to the BankAccount structure. In the Debit function, we’ll use Lock and Unlock on rwm because we’re both reading and modifying the balance. In GetBalance, we’ll use RLock and RUnlock, blocking only for reading, leaving it open for writing, and boosting performance overall. Here’s the updated code:

And, of course, we’ll run the test again with the --race flag to confirm that the problem is solved. Check out the results in the image below.

Congratulations, Gopher! Another race condition resolved elegantly.

Once

The sync package also brings us the Once structure, which is the key to executing a function only once, even if multiple goroutines try to call it simultaneously. It’s perfect for scenarios where you need to ensure that something only happens a single time, like singleton initialization. Remember the Connector example from the previous post? Let’s revisit it for a quick refresher.

This code creates two connectors with different attempts (attempt 1 and attempt 5) because checking for nil on conn alone doesn’t work. To fix this, we’ll add a new once variable of type sync.Once right below conn and use the Do function to initialize the connector. Now, regardless of the number of calls, the connector will be created only once. See the updated code:

And with the --race test enabled, you’ll see the code is free from race conditions. Check the image below.

Conclusion

These sync package structures — RWMutex and Once — are essential for building safe and performant Go applications. RWMutex provides refined control over read and write locks, improving efficiency and reducing deadlock risks. Once, on the other hand, is perfect for safe, one-time initializations, ideal for preventing resource duplication. With these, you’re much better equipped to navigate the challenges of concurrent programming.

Keep exploring and learning, Gopher! After all, the road of programming is long, but with Go, it’s a bit more fun and efficient.

Andre de Oliveira

Senior Software Engineer | Golang Developer | Node.js | React |Microservices | DevOps

2 个月

Another amazing article on using concurrency properly! Great content!

回复
Patrick Cunha

Lead Fullstack Engineer | Typescript Software Engineer | Nestjs | Nodejs | Reactjs | AWS | Rust

3 个月

Awesome

回复
Jefferson Luiz

FullStack Developer @ Itaú Digital Assets | Go | TS | Blockchain | Aws

3 个月

Great advice

回复
Rodrigo Tenório

Senior Software Engineer | Java | Spring | AWS

3 个月

I'll keep this in mind

回复
Miguel Angelo

Data Engineer | Analytics Engineer | Python SQL AWS Databricks Snowflake

3 个月

Very helpful!

回复

要查看或添加评论,请登录

Vagner Nascimento的更多文章

社区洞察

其他会员也浏览了