Hacker News new | ask | show | jobs
by scottlamb 1475 days ago
> So it's not practical to create 100s of Ks of goroutines - it's possible, sure, but because you incur GBs of memory overhead if you are actually creating that many goroutines means that for any practical problem you are going to want to stick to a few thousand goroutines. I can almost guarantee you that you have something better to do with those GBs of memory than store goroutine stacks.

You lost me in a couple places:

1) "GBs of memory overhead" being a lot. A rule of thumb I've seen in a datacenter situation is that (iirc) 1 hyperthread and 6 GiB of RAM are roughly equivalent in cost. (I'm sure it varies over processor/RAM generations, so you should probably check this on your platform rather than take my word for it.) I think most engineers are way too stingy with RAM. It often makes sense to use more of it to reduce CPU, and to just spend it on developer convenience. Additionally, often one goroutine matches up to one incoming or outgoing socket connection (see below). How much RAM are you spending per connection on socket buffers? Probably a lot more than a few kilobytes...

2) The idea that you target a certain number of goroutines. They model some activity, often a connection or request. I don't target a certain number of those; I target filling the machine. (Either the most constrained resource of CPU/RAM/SSD/disk/network if you're the only thing running there, or a decent chunk of it with Kubernetes or whatever, bin-packing to use all dimensions of the machine as best as possible.) Unless the goroutines' work is exclusively CPU-bound, of course, then you want them to match the number of CPUs available, so thousands is too much already.

2 comments

I agree that GBs for 100Ks of go routines is not in some sense "a lot", in that you might still be using memory pretty effectively. But I don't see that a "6GB vs 1 core" tradeoff makes any sense to talk about.

We have HTTP ingress that needs ~100 cores but could theoretically all fit in 1GB. We have k/v stores that need only 16 cores but would like 500GB. And we have data points at most places in-between. We can't give the ingress 600GB instead, and we can't give the k/v stores 100 cores. So the fact they're financially interchangeable is meaningless for capacity planning.

Arguably, for most code and especially in a GCd language, using less memory and less CPU go hand-in-hand.

If you are in aggregate making good use of all the dimensions of the available machines/VMs, great. I think often people either leave one dimension unused or (when buying their own hardware / selecting a VM shape) could be adding more RAM cheaply.

> Arguably, for most code and especially in a GCd language, using less memory and less CPU go hand-in-hand.

Agreed in general. Even in a non-GC language, less dense data structures means worse CPU cache utilization. But on the other hand, memoization and the like can provide a real trade-off.

In this case, I don't think it's costing much CPU. The GC isn't traversing beyond the bounds of the stack, and it mostly shouldn't end up in the CPU cache either. (Just a partial cache line at the boundary, and some more after a goroutine's stack shrinks or the goroutine exits.)

> I think most engineers are way too stingy with RAM. It often makes sense to use more of it to reduce CPU, and to just spend it on developer convenience.

Hey! That's Java's argument!