#waitgroup
💡 Summary:

Goの並行処理を解説するミニ本で、Goroutine、Channel、Select、Pipelines、Time、Context、WaitGroup、Mutexなど主要 topics の概要と実用的なサンプルがまとまっています。初心者向けではなく、実践的な復習用として設計されています。
September 27, 2026 at 5:44 PM
【第5回】実務的な周辺技術 ── Docker・設定・ログ・認証・並行処理

シリーズ構成 Go の基本文法 CLI ツールを作る HTTP サーバーと REST API データベース連携 実務的な周辺技術(本記事) ポートフォリオを作る 実践知識を深める この回の目標は 「API を本番相当の構成で動かせるようにし、Go の並行処理を自信を持って書けるようになる」 ことです。 前半は運用に必要な道具(Docker・設定・ログ・認証・lint)、後半は Go の最大の武器である 並行処理…
【第5回】実務的な周辺技術 ── Docker・設定・ログ・認証・並行処理
シリーズ構成 Go の基本文法 CLI ツールを作る HTTP サーバーと REST API データベース連携 実務的な周辺技術(本記事) ポートフォリオを作る 実践知識を深める この回の目標は 「API を本番相当の構成で動かせるようにし、Go の並行処理を自信を持って書けるようになる」 ことです。 前半は運用に必要な道具(Docker・設定・ログ・認証・lint)、後半は Go の最大の武器である 並行処理 を体系的に扱います。並行処理はこの記事の中で最も長い章ですが、バックエンドエンジニアとして避けて通れない部分です。 目次 Part 1:運用のための道具 Docker とマルチステージビルド Docker Compose で開発環境を作る 設定管理(環境変数) 構造化ログ(log/slog) 認証:パスワードハッシュと JWT Makefile・lint・CI Part 2:並行処理7. goroutine の基礎と落とし穴8. sync パッケージ:Mutex・RWMutex・WaitGroup・Once9. channel の設計10. select11. context:キャンセルとタイムアウト12. 並行処理パターン集13. errgroup14. データ競合の検出とデバッグ15. 演習問題 Part 1:運用のための道具
analyzegear.co.jp
September 22, 2026 at 6:00 AM
Went back to the video, you did a great job explaining WaitGroup. I’m just struggling to implement nonblocking/blocking simultaneous/unrelated processes for a project. There are resources on the topic already, but I learn best through content.

(I just wish Go had more tutorials in general tbh)
September 14, 2026 at 7:02 PM
More favorites from go.dev/doc/go1.25:

- go doc -http
- waitgroup analyzer
- experimental encoding/json/v2
- trace flight recorder
- CrossOriginProtection, of course
- 3x faster RSA keygen
- no more SHA-1 in TLS 1.2
- hash.Cloner and XOF
- more os.Root methods
- WaitGroup.Go (!)
- testing.T.Output
Go 1.25 Release Notes - The Go Programming Language
go.dev
August 13, 2025 at 7:29 AM
Oh boy. I have some Go code (a Goroutine) deferring a `Done()` call on a WaitGroup, and it's...not being called!

Main isn't done executing (if it were this wouldn't really matter) and the Goroutine isn't panicking, so...time to do some digging.
December 5, 2024 at 5:39 PM
I have hit this exact class of bug in async workers. We ended up wrapping WaitGroup style joins with a bounded semaphore plus timeout metrics, because one missing Done can pin capacity and look like random latency elsewhere.
April 19, 2026 at 8:00 AM
Mastering Go Concurrency Primitives: A Practical Guide
#### 1. Intro: Why Go Concurrency Primitives Matter Go’s concurrency model is a developer’s dream—goroutines and channels make parallel programming feel effortless. But in the real world, they’re not always enough. Enter the `sync` package: a toolkit of concurrency primitives like `Mutex`, `RWMutex`, `WaitGroup`, and `sync.Pool` that can turbocharge performance or save you from subtle bugs. If you’ve got 1-2 years of Go under your belt, you’re probably comfy with goroutines and channels. But when faced with a high-traffic web server or a tricky task scheduler, questions creep in: _Should I use`Mutex` or `RWMutex`? Does `sync.Pool` really help?_ Pick wrong, and your app’s performance tanks. In this guide, we’ll break down these primitives with benchmarks, real-world tips, and a handy selection cheat sheet. I’ll share lessons from my own projects—like the time a `Mutex` bottleneck crushed my QPS—so you can dodge the same traps. Let’s dive in and level up your Go concurrency game! #### 2. The Concurrency Toolbox: A Quick Rundown Go’s mantra—“Don’t communicate by sharing memory; share memory by communicating”—is gold. Goroutines and channels nail that vibe, but the `sync` package offers precision tools for trickier spots. Here’s the lineup: * **`sync.Mutex`** : Locks a resource so only one goroutine touches it. Simple, exclusive access. * **`sync.RWMutex`** : Allows multiple reads or one write—great for read-heavy workloads. * **`sync.WaitGroup`** : Waits for a batch of goroutines to finish. Think “task herder.” * **`sync.Pool`** : Reuses objects (like buffers) to dodge memory allocation overhead. Each has a superpower, but performance hinges on _how_ you use them: lock scope, contention, and read/write patterns. Let’s see them in action with some benchmarks. #### 3. Performance Showdown: Benchmarks Tell All I ran these tests on an 8-core Linux box with Go’s `testing` package—simulating real workloads. Code’s at the end if you want to play along! ##### 3.1 `Mutex` vs `RWMutex` **Setup** : A cache with 90% reads, 10% writes. **Code** : var cache = map[int]int{1: 100} func BenchmarkMutex(b *testing.B) { var mu sync.Mutex b.RunParallel(func(pb *testing.PB) { for pb.Next() { mu.Lock() _ = cache[1] // Read mu.Unlock() } }) } func BenchmarkRWMutex(b *testing.B) { var rwmu sync.RWMutex b.RunParallel(func(pb *testing.PB) { for pb.Next() { rwmu.RLock() _ = cache[1] // Read rwmu.RUnlock() } }) } **Result** : `RWMutex` smoked `Mutex` with ~40% more throughput. Why? It lets multiple reads happen at once—`Mutex` forces a queue. ##### 3.2 `WaitGroup` vs DIY Counting **Setup** : Sync 10 goroutine tasks. **Result** : `WaitGroup` matched a manual counter’s speed but was way cleaner—no channel juggling or atomic hacks needed. ##### 3.3 `sync.Pool` vs No Pool **Setup** : Reusing buffers in a mock HTTP service. **Code** : var pool = sync.Pool{New: func() interface{} { return make([]byte, 1024) }} func BenchmarkPool(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { buf := pool.Get().([]byte) pool.Put(buf) } }) } **Result** : `sync.Pool` slashed memory allocations by ~30%, easing GC pressure. **Takeaway Table** : Tool | Best Case | Speed Boost ---|---|--- `Mutex` | Simple locks | Baseline `RWMutex` | 70%+ reads | 30-50% faster `WaitGroup` | Task sync | Clean + fast `sync.Pool` | High allocations | 20-40% GC relief **War Story** : In a logging app, `Mutex` on a shared cache dropped QPS from 8000 to 5000. Switching to `RWMutex` fixed it—reads shouldn’t wait! #### 4. Picking Your Weapon: A Selection Guide Choosing a primitive isn’t rocket science—it’s about matching the tool to the job. Here’s how: ##### 4.1 Rules of Thumb * **Low Contention** : `Mutex` is your no-fuss buddy. * **Read-Heavy** : `RWMutex` if reads hit 70%+. * **Task Sync** : `WaitGroup` for simplicity. * **Memory Crunch** : `sync.Pool` for reusing stuff. ##### 4.2 Real Examples * **Web Cache** : Use `RWMutex` for tons of reads, rare writes. type Cache struct { mu sync.RWMutex data map[string]string } func (c *Cache) Get(key string) string { c.mu.RLock() defer c.mu.RUnlock() return c.data[key] } * **Task Batch** : `WaitGroup` keeps it tidy. func ProcessTasks(tasks []Task) { var wg sync.WaitGroup for _, t := range tasks { wg.Add(1) go func(task Task) { defer wg.Done() task.Run() }(t) } wg.Wait() } * **Logging** : `sync.Pool` for buffer reuse. var pool = sync.Pool{New: func() interface{} { return make([]byte, 1024) }} func Log(msg string) { buf := pool.Get().([]byte) defer pool.Put(buf) // Use buf... } #### 5. Best Practices: Winning at Concurrency Theory’s great, but practice is where the rubber meets the road. Here are some battle-tested tips—plus a few “oops” moments I’ve survived—to make your Go concurrency shine. ##### 5.1 Lock Smarter, Not Harder Keep locked sections tiny—don’t hog the bathroom when you’re just brushing your teeth! type Counter struct { mu sync.Mutex count int } func (c *Counter) Inc() { c.mu.Lock() defer c.mu.Unlock() // Unlock ASAP c.count++ } **Lesson** : In a task queue, I locked the whole thing with one `Mutex`—throughput crashed to 3000 QPS. Splitting locks by task ID doubled it to 7000. Smaller locks = more concurrency. ##### 5.2 Cap Those Goroutines Spawning goroutines like rabbits can choke your app. Use a worker pool to tame them. func WorkerPool(tasks []Task, max int) { var wg sync.WaitGroup sem := make(chan struct{}, max) // Limit to `max` workers for _, t := range tasks { sem <- struct{}{} // Grab a slot wg.Add(1) go func(task Task) { defer wg.Done() defer func() { <-sem }() // Free the slot task.Run() }(t) } wg.Wait() } **War Story** : A service hit 10GB RAM from unchecked goroutines. Capping at 100 workers dropped it to 2GB—crisis averted! ##### 5.3 Nail `sync.Pool` Reuse objects right, or you’ll leak data. var pool = sync.Pool{New: func() interface{} { return make([]byte, 1024) }} func Log(msg string) { buf := pool.Get().([]byte) defer pool.Put(buf) copy(buf, []byte(msg)) // Reset or copy—don’t assume clean! } **Gotcha** : I skipped resetting buffers in a logger—old logs bled into new ones. A quick `copy` fixed it. **Quick Tips** : * Always `defer Unlock()`—no deadlocks. * Test `RWMutex`—it’s overkill if writes match reads. * `WaitGroup`: Call `Add` _before_ goroutines start. #### 6. Case Study: Saving an E-commerce Backend ##### 6.1 The Mess Imagine an e-commerce order system—millions of orders, Black Friday traffic. The original setup used a single `Mutex` for the order cache. At 2000 QPS and 50ms latency, it buckled under peak load—5% timeouts killed sales. ##### 6.2 The Fix We overhauled it with three moves: 1. **`RWMutex`** : Swapped `Mutex` for concurrent reads (90% of traffic). 2. **`sync.Pool`** : Reused order objects, slashing GC load. 3. **`WaitGroup`** : Synced bulk updates cleanly. **Code** : type OrderCache struct { data map[int]*Order mu sync.RWMutex pool sync.Pool } func NewOrderCache() *OrderCache { return &OrderCache{ data: make(map[int]*Order), pool: sync.Pool{New: func() interface{} { return &Order{} }}, } } func (c *OrderCache) Get(id int) *Order { c.mu.RLock() defer c.mu.RUnlock() return c.data[id] } func (c *OrderCache) Update(orders []*Order) { var wg sync.WaitGroup for _, o := range orders { wg.Add(1) go func(order *Order) { defer wg.Done() buf := c.pool.Get().(*Order) buf.ID, buf.Status = order.ID, order.Status c.mu.Lock() c.data[buf.ID] = buf c.mu.Unlock() }(o) } wg.Wait() } ##### 6.3 The Win QPS doubled to 4000, latency dropped to 15ms, and timeouts fell to 0.5%. GC overhead shrank from 8% to 2%—happy shoppers, happy servers! **Before vs After** : Metric | Before | After | Gain ---|---|---|--- QPS | 2000 | 4000 | +100% Latency (ms) | 50 | 15 | -70% Timeouts (%) | 5 | 0.5 | -90% **Takeaway** : Combining tools beat any single fix. Benchmarks guided us—`RWMutex` alone gave a 40% lift. #### 7. Wrap-Up: Your Concurrency Compass ##### 7.1 What We Learned * **`RWMutex`** : King of read-heavy (70%+ reads). * **`WaitGroup`** : Sync made simple. * **`sync.Pool`** : GC’s kryptonite for high allocations. * **Test, Don’t Guess** : Benchmarks and real data rule. ##### 7.2 What’s Next? Go’s concurrency is evolving—think `context`-driven locks or smarter `sync.Pool` sizing. Keep an eye on `golang.org/x/sync` for extra goodies. ##### 7.3 Your Toolkit * **Start** : Play with these in small projects. * **Measure** : Use `testing.Benchmark` and `pprof`. * **Learn** : Dig into Go blogs or GopherCon vids. **Cheat Sheet** : Tool | Use When | Beware ---|---|--- `Mutex` | Simple locks | Read queues `RWMutex` | Lots of reads | Write-heavy waste `WaitGroup` | Task batches | `Add` order `sync.Pool` | Reuse objects | Reset discipline Concurrency’s an art—experiment, fail, and tweak. Got a favorite primitive or epic bug story? Drop it in the comments—I’d love to hear! Happy coding!
forem.com
May 14, 2025 at 1:48 AM
Here’s async #golang in a single skeet: put the “go” keyword in front of it. Use a WaitGroup if you need to coordinate, use channels if you need to communicate
October 23, 2024 at 9:41 PM
#後で読む 用メモです→
Go入門 #10並行処理の基礎 goroutinechannelWaitGroup
【Go入門 #10】並行処理の基礎 〜goroutine・channel・WaitGroup〜
zenn.dev
July 26, 2026 at 1:34 AM
Deep Dive into WaitGroup: Mastering Concurrent Task Orchestration in Go
#golang

dev.to/jones_charl...
Deep Dive into WaitGroup: Mastering Concurrent Task Orchestration in Go
1. Introduction Go’s concurrency model is a game-changer—goroutines and channels make...
dev.to
June 9, 2025 at 6:00 PM
An interesting article about "Fail-Fast Testing of Goroutines with WaitGroup and time.After"
#golang

juanpabloaj.substack.com/p/fail-fast...
April 26, 2025 at 7:33 AM
E como to.criando goroutines, preciso esperar elas terminarem. Então uso un waitgroup:

var wg sync.WaitGroup
wg.Add(len(teams))

E dentro da goroutine eu chamo wg.Done() quando ela termina

Fora do for loop eu chamo wg.Wait() para esperar todas elas terminarem o trabalho.
October 28, 2024 at 1:39 AM
figuring out how to handle recurring payments through stripe in golang has been pretty fun

Look how clean this is

#golang #pocketbase #stripe
March 19, 2025 at 6:28 AM
As you may know, Go 1.26 RC was released last week. Before starting to use it, it can be interesting to look at some features introduced in Go 1.25, such as WaitGroup.Go(), which makes working with goroutines cleaner and safer. notdefine.dev/waitgroup-go/ #golang
WaitGroup.Go()  - NotDefine.dev
At the moment, Go 1.26 is in RC, but before looking at the new features, it may be useful to review something that was introduced in Go 1.25. In this post, we look at WaitGroup.Go(). The purpose of th...
notdefine.dev
January 19, 2026 at 7:27 AM
"we have wait groups at home"
October 19, 2025 at 11:46 AM