The Applied Go Weekly Newsletter logo

The Applied Go Weekly Newsletter

Subscribe
Archives
June 29, 2025

Know Your (CPU) Limits! • The Applied Go Weekly Newsletter 2025-06-29

AppliedGoNewsletterHeader640.png

Your weekly source of Go news, tips, and projects

2025-06-29 Newsletter Badge.png

Know Your (CPU) Limits!

Hi ,

Living beyond one's means is rarely a smart move. But it's easy to get their if you aren't aware of your limits.

Go apps have this problem inside containers, as they can't see their true limits and assume more resources than they actually can access. Not with Go 1.25, though, thanks to the new (and much more nuanced) behavior of GOMAXPROCS().

This is one of the new features in Go 1.25, explained in this issue's Spotlight. I'm also happy to share another "Go 1.x interactive tour" by Anton Zhiyanov that lets you test out all new Go 1.25 features live in the browser. This time, Anton forked the JSON v2 part out of the main tour because of the many changes in the new v2 API.

The downside: You have to wait until August to see all these shiny new changes live in mainstream Go (but the interactive tour and the Go 1.25 release candidates help to fill the time until the final release).

Happy coding!

–Christoph

Featured articles

JSON evolution in Go: from v1 to v2

JSON v2 is coming! New features, fixed issues, and generally faster. With Go 1.25, JSON v2 will become available as an experimental package. Test it out in Anton's new interactive article!

Go 1.25 interactive tour

The Go 1.25 release notes are out but lack the hands-on experience that you can have with this interactive tour.

From Scarcity to Abundance: How Go Changed Concurrency Forever | by Ashish Khuraishy | Jun, 2025 | Medium

What were your feelings when moving from POSIX system threads to goroutines? Did you miss the bulkiness of POSIX threads and the many knobs you can (and need) to turn to carefully balance threads against available resources (mainly, CPUs)? Indeed, goroutines introduced a paradigm shift toward lightness and ease of use. Ashish Khuraishy explores the consequences of this paradigm shift.

Podcast corner

Cup o' Go: What's coming in Go 1.25? Plus Redowan Delowar on what makes Go different from other languages

Redowan Delowar, a.k.a rednafi, is this episode's guest, talking to Jonathan and Shay about Vault, Go, and his recent article about dependency injection frameworks (See the newsletter issue from June 1st).

Fallthrough: The Three Ps: Understanding Product, Project, and Program Management

Are the roles "product manager", "program manager", and "project manager" clearly defined in your company? Uh, why should they ... they're manager roles, and manager roles are never well-defined, are they? Moreover, product managers shouldn't even exist, leaving us with only two roles to define... Just kidding. Kris, Ian, Matthew, and Angelica try to give these roles a sharper definition.

Spotlight: Container-Aware GOMAXPROCS (New in Go 1.25)

The simple world before container runtimes

Once upon a time, there was a new programming language named Go with built-in concurrency. It lived in a simple world: Docker and Kubernetes did not exist back then (obviously, as both are written in Go); and so, a CPU was a CPU.

A Go app knew how many CPU cores it could use by calling runtime.GOMAXPROCS(0), which returns the number of logical CPU cores available to the process. This number was gathered once at the start of the process and never changed throughout the process's lifetime. The app could use this information to manage workload; for example, by spawning an appropriate number of goroutines based on the CPU count.

A Go app also could artificially restrict the number of CPUs available by calling runtime.GOMAXPROCS(n) where n > 0.

My CPU count isn't your CPU count

All was well until containers entered the scene—especially, container runtimes like Kubernetes. At this point, things turned tricky. Container runtimes isolate processes to achieve a replicable behavior, enhanced security, and control of resource usage (among other goals).

One of the isolation techniques is based on Linux's Control Groups, or cgroups. A cgroup controls how much of a given resource a process can use. CPUs are such resources. Container runtimes use cgroups to impose a limit of CPU bandwidth available to a containerized process.

When containerized Go apps were CPU-limited this way, a tiny problem surfaced: GOMAXPROCS(0) led the app to believe it has much more CPU power available than it actually had.

Imagine you have:

  • A server with 16 CPU cores
  • A container that's limited to use only 2 cores worth of CPU time
  • A Go app running inside that container

The app would assume it has 16 CPUs available and try to use this amount to manage its workload, but actually, all the workload would run on 2 cores worth of CPU time.

You guess what happens: poor performance and resource contention. Time was ripe for fixing this problem.

Count smarter, be happier

With Go 1.25, the behavior of GOMAXPROCS() dramatically changes (and so does the size of the function documentation). Well, maybe not dramatically, but using adjectives like this is a great way of maintaining the reader's attention. (You still here?)

So, the Go 1.25 runtime understands cgroups, and inside a container, GOMAXPROCS() defaults to the CPU limit the container runtime imposes. So if Kubernetes generously grants your app 4.5 CPU cores worth of CPU time, the app will assume 4 available CPU cores (rounded down, because fractional cores are kind of a BS from the perspective of scheduling goroutines to CPU cores).

Moreover, GOMAXPROCS() isn't updated only at process startup time but periodically adjusted to any changes to the CPU bandwidth. Say, if Kubernetes increases or decreases CPU bandwidth, the Go runtime can follow along, as can the app if it queries GOMAXPROCS() for the current amount of CPU cores.

Worth noting that Go ignores Kubernetes' "CPU requests" setting, so this configuration...

resources:
  limits:
    cpu: "2"      # This is what Go 1.25 respects
  requests:
    cpu: "1"      # Go ignores this

...would have GOMAXPROCS(0) return 2, based on the limits configuration only.

See also the Go 1.25 release notes on GOMAXPROCS.

Happy navigating, dear κυβερνήτης!

Quote of the Week: This Would Be Madness

I’ve seen Go programs that spawn a goroutine for every line in a log file, launch hundreds of goroutines to process a batch job, or create a dedicated goroutine just to handle cleanup for a single request. In any other language, this would be madness.

In Go, it’s Tuesday.

–Ashish Khuraishy

More articles, videos, talks

Go should be more opinionated

Go is a quite opinionated language, but Elton Minetto thinks it should be even more opinionated.

Finding performance problems by diffing two Go profiles

Hunting down a performance issue can be tedious, even with pprof profiles ... unless you have a base profile to compare against.

HTTP/3 Series | Software Engineering & Personal Thoughts

This series introduces the reader to using HTTP/3 in Go, based on the author's explorations and aiming at saving the reader from stumbling over the quirks the author discovered in their journey.

Writing Parallel File Compression with Memory Control

Programs, and especially concurrent ones, need to stay aware of resource consumption. Sushant Dhiman uses a memory-aware semaphore system to ensure his concurrent file compression tool doesn't become memory-greedy.

Error handling

A Go monk never errs. And if they do, they know how to meditate over them. Because, after all, errors are just values.

Zombie Zen - Why Go Rocks for Building a Lua Interpreter

So the available Lua interpreters don't meet your needs? Write your own! Roxy Light did exactly this and shares their learnings in this article.

Projects

Libraries

GitHub - maypok86/otter: A high performance caching library for Go

Not just a major update but almost completely reworked for a better API and richer features while maintaining high performance.

GitHub - Kairum-Labs/should: Fluent and expressive assertions for Go. Make your tests readable, elegant, and easy to debug.

should generates user-friendly and readable output, driven by the author's experience with other assertion libraries whose output isn't as helpful or readable as it could be.

Tools and applications

Conway's Game of life

  1. Create a Gosper Glider Gun
  2. Click "Center"
  3. Create a second Gosper Glider Gun
  4. Enjoy watching!

GitHub - rednafi/q: A fast command-line interface for chatting with language models.

Yet another CLI for LLM chats? Sure, why not. Redowan Delowar wrote it as he missed some features in other LLM CLI tools.

Pet The Pixel

"this is the most overengineered piece of trivial software that does nothing i've ever seen" - /u/kova98k

GitHub - Jay-Madden/auto-fix-return.nvim: Neovim plugin to automatically add or remove Go function return parenthesis dynamically as you type

Neovim users who switched from GoLand kept missing this one little feature until this plugin came out! (Well, I know of two, at least.)

Runal

Like Processing or p5.js but for the terminal... and for Go code! Make ASCII art with Go (or JavaScript, if you feel like it).

GitHub - andreybleme/lazycontainer: Fancy terminal UI for Apple Containers

A TerminalUI frontend (WIP) for Apple's container-on-Apple-Silicon project (WIP).

GitHub - jonas-grgt/ktea: Kafka TUI client

ktea aims to be for Kafka what k9s is for Kubernetes.

Completely unrelated to Go

Beauty Is Objective

Beauty is in the eye of the beholder. Or is it? Andrew Coyle claims that beauty isn't arbitrary like taste but based on universal principles of coherence, proportion, and pattern.

Happy coding! ʕ◔ϖ◔ʔ

Questions or feedback? Drop me a line. I'd love to hear from you.

Best from Munich, Christoph

Not a subscriber yet?

If you read this newsletter issue online, or if someone forwarded the newsletter to you, subscribe for regular updates to get every new issue earlier than the online version, and more reliable than an occasional forwarding. 

Find the subscription form at the end of this page.

How I can help

If you're looking for more useful content around Go, here are some ways I can help you become a better Gopher (or a Gopher at all):

On AppliedGo.net, I blog about Go projects, algorithms and data structures in Go, and other fun stuff.

Or visit the AppliedGo.com blog and learn about language specifics, Go updates, and programming-related stuff. 

My AppliedGo YouTube channel hosts quick tip and crash course videos that help you get more productive and creative with Go.

Enroll in my Go course for developers that stands out for its intense use of animated graphics for explaining abstract concepts in an intuitive way. Numerous short and concise lectures allow you to schedule your learning flow as you like.

Check it out.


Christoph Berger IT Products and Services
Dachauer Straße 29
Bergkirchen
Germany

Don't miss what's next. Subscribe to The Applied Go Weekly Newsletter:
LinkedIn
Powered by Buttondown, the easiest way to start and grow your newsletter.