News for hackers. Stuff that matters.
Re:Why you can have millions of goroutines but only thousand... by weberc2 on Monday October 08, 2018 @11:04PM (#18173016)
These are good questions and I'd be interested in more authoritative answers, but I'll hazard guesses.

1. Go's scheduler is better at scheduling Go. There are well defined points at which a context switch can occur, and the scheduler is in userland so you never really have expensive context switches.

2. Not sure. I would guess so, if only because it saves a couple context switches.

3. Goroutines are absolutely relevant for both. The stdlib webserver is a high-performance, production-grade implementation and it forks a goroutine for each request, and applications frequently fork more goroutines within a request handler.

4. I assume you're comparing Go channels to pipes? In which case the answer is probably always "faster", but how much faster depends on the size of the thing you're transferring since IPC requires serialization and deserialization while in Go the overhead is just some locking and a pointer copy.

5. Go has dynamically-sized stacks. While you can change stack size on Linux (to use very small stacks and thus spin up more threads), I don't think you can change the size of an individual stack. Plus with Go, you don't have to configure stack size at all; it works out of the box on every platform.

For me, that Go's goroutines are performant is just gravy. I like that they're a platform agnostic concurrency abstraction. I don't have to deal with sync vs async ("What color is your function"; which incidentally cost me the last 1.5 workdays tracking down a performance bug in Python) or posix threads vs Windows threads.

Re:Why you can have millions of goroutines but only thousand... by gpderetta on Tuesday October 09, 2018 @05:08AM (#18174357)
Re 5: pthread allows setting the stack size of each individual thread although this is seldom done in practice as on 64 bit address space is not at premium.

GCC also, on some platforms, allows using segmented stacks on any C and C++ programs which means that a thread will only use only as much physical and virtual memory as required. I don't think segmented stacks have seen much use though as they have non zero cost and, for optimal space usage, ideally require recompiling any dependncy, including glibc with them.

Interestingly segmented stacks were implemented to support GCCGO.

Re:Why you can have millions of goroutines but only thousand... by ridiculous_fish on Monday October 08, 2018 @11:18PM (#18173061)
How does Go handle non-async syscalls these days? If you spawn a thousand goroutines which all call stat(), does this still spawn a thousand kernel threads?

This took some of the bloom off the rose for me. For each goroutine I had to predict ahead-of-time whether it would require a kernel thread, and if so send it through a rate limiter. Effectively it was sync-vs-async but hidden.

Re:Why you can have millions of goroutines but only thousand... by denormalfloat on Monday October 08, 2018 @11:53PM (#18173199)
Yes, it spawns a kernel thread if all the threads are currently blocked. I ran into this issue running Go on a FUSE mounted file system. If the network hung, Go would spawn thousands of threads and OOM. Go can't _not_ spawn them, as that would risk deadlock.
Re:Why you can have millions of goroutines but only thousand... by toast0 on Tuesday October 09, 2018 @01:48AM (#18173610)
(disclaimer: I know very little about Go)

An expected way to manage this would be to have a limit on the number of threads to run blocking syscalls. Up to you how to do it (threadpool for syscalls, anythrrad can run a syscalls but checks a mutex first, etc)

I don't think there's a danger of deadlocks here -- your blocking syscalls shouldn't be dependant on other goroutines. Eventually the calls will succeed or timeout (one hopes) and the next call will commence.

In my experience, you can usually find a safe number of parallel syscalls to run -- and it's often not very many.

Re:Why you can have millions of goroutines but only thousand... by ridiculous_fish on Tuesday October 09, 2018 @03:02AM (#18173867)
Imagine 1000 pipes, each of which has a goroutine calling write() and another calling read(). If you schedule all of the writers and none of the readers (or vice versa) you'll get a deadlock.
Re:Why you can have millions of goroutines but only thousand... by leaveyou on Tuesday October 09, 2018 @03:51AM (#18174057)
AFAIK when a goroutine "calls write" (on a channel or on a socket, stream, mutex etc).. and the write "is blocked" it yields the execution and the scheduler can activate something else.. which can be a reader goroutine (after all the writers are blocked for example). So there's no deadlock as long as you have at least one reader for any writer.
Re:Why you can have millions of goroutines but only thousand... by gpderetta on Tuesday October 09, 2018 @05:13AM (#18174383)
That requires the underlying syscall to support an async or non blocking mode though. Disk io or stat doesn't on linux for example. The usual alternative is some sort of background pool for blocking tasks (which adds non trivial overhead), or, where supported by the OS, scheduler activation.
Re:Why you can have millions of goroutines but only thousand... by leaveyou on Tuesday October 09, 2018 @06:11AM (#18174611)
You are right, see Synchronous System Calls in

https://www.ardanlabs.com/blog/2018/08/scheduling-in-go-part...

Re:Why you can have millions of goroutines but only thousand... by toast0 on Tuesday October 09, 2018 @09:17AM (#18175671)
Sorry, I also expected those things that can be translated into non-blocking calls with select-ish apis for readiness to be translated as well -- because it's the right thing to do in this type of environment.

To be more specific, most socket calls should be async + selectish, but file system calls would likely be done as synchronous, because async doesn't generally work for that -- anyway limiting the number of outstanding file I/O requests tends to help throughput.

Re:Why you can have millions of goroutines but only thousand... by zbentley on Tuesday October 09, 2018 @02:26PM (#18178520)
stat() cannot (on platforms I am familiar with) be performed in a selectish/nonblocking way. That call can block forever. Local filesystem access in general is still not async-capable in very important ways.
Re:Why you can have millions of goroutines but only thousand... by toast0 on Wednesday October 10, 2018 @02:00AM (#18182365)
Yes, filesystem calls are going to block -- but putting that into a limited threadpool shouldn't deadlock your system -- you can't do a blocking read on a file, waiting for it to be filled by another thread (unless/until you start playing with FUSE, I guess.
Re:Why you can have millions of goroutines but only thousand... by keepingscore on Tuesday October 09, 2018 @09:07AM (#18175582)
Re 3. Funny you should mention net http's goroutine per request model. Fasthttp massively out performs stdlib on every techemporer benchmark using a goroutine/worker pool model.

https://stackoverflow.com/questions/41627931/in-golang-packa...

https://www.techempower.com/benchmarks/

http://marcio.io/2015/07/handling-1-million-requests-per-min...

Re:Why you can have millions of goroutines but only thousand... by weberc2 on Tuesday October 09, 2018 @09:15AM (#18175652)
To be clear, that doesn’t invalidate my claim (goroutines per request are suitable, not maximally performant).
Re:Why you can have millions of goroutines but only thousand... by optician_owl on Monday October 08, 2018 @11:53PM (#18173200)
> so you never really have expensive context switches

It can be possible only if there are no more "physical" threads than cores. And anyway a switching between async routines on the same "physical" thread requires a switching of routines contexts (go to the memory and update cashes).