Earlier quoted context omitted.
I'm of the impression that there's an important difference between Go and Haskell's models--namely that Go is M:N threaded and Haskell is not; however, I don't entirely understand the significance of the difference, so hopefully someone else can comment and enlighten me.
Are you sure about Haskell not having m:n threads? Because it's seems weird, considering GHC is listed as one of a few examples on wikipedia: https://en.m.wikipedia.org/wiki/Thread_(computing)#M:N_.28hy...
Evio – Fast event-loop networking for Go
61–67 of 67 posts
Re: Evio – Fast event-loop networking for Go
#62Earlier quoted context omitted.
Goroutines are threads. They're just not kernel-level threads. There have been implementations of pthreads that used an M:N model, for instance.
For my information, why is M:N so successful for Go and not for pthreads? Is M:N more practical for systems with a particular kind of garbage collector?
I'm not convinced that 1:1 wouldn't have been a perfectly reasonable implementation strategy for Go.
Re: Evio – Fast event-loop networking for Go
#63Earlier quoted context omitted.
It's not nearly as simple as you claim. First: if you have an epoll loop it is also the cost of the thread context switch, which has definitely us in RPC systems using kernel threads. By contrast the goroutine gets scheduled onto the kernel thread that answered the poll, saving the switch. Second: as I alluded to earlier, linux and solaris can scale their kernel thread implementations, not all OSs can. My experiences…
> First: if you have an epoll loop it is also the cost of the thread context switch, which has definitely us in RPC systems using kernel threads. By contrast the goroutine gets scheduled onto the kernel thread that answered the poll, saving the switch. I'm not comparing M:N to a 1:1 system where all I/O is proxied out to another thread sitting in an epoll loop. I'm comparing M:N to 1:1 with blocking I/O. In this scen…
Second, almost all the event-driven C++ servers I have seen are written that way not for performance, but for scaling and latency. There is usually plenty of extra CPU and RAM, only a tiny fraction really bump up against resource limits. (A typical case of the vast majority of code not being performance sensitive.)
Otherwise, I agree with your points in this comment. Especially the broader point that there's no novel component of Go. Go is about combining well-known things together.
However, it seems to me that Go still cuts through the "threads vs. events" argument in a way nothing else does. I can write code in a blocking style using typical libraries, and have it scale to large numbers of active connections.
On other systems the implementations don't scale or I have to heavily restrict library use based on stack growth, or I am tied to a particular OS. It seems to me the only alternatives to Go's nice blocking code environment require significant compromise or require something to be built.
Re: Evio – Fast event-loop networking for Go
#64Earlier quoted context omitted.
For my information, why is M:N so successful for Go and not for pthreads? Is M:N more practical for systems with a particular kind of garbage collector?
In my opinion, it's because the Go team put a ton of effort into getting M:N working and didn't rigorously evaluate any other alternatives in Go , once moving GC was implemented. I'm not convinced that 1:1 wouldn't have been a perfectly reasonable implementation strategy for Go.
Re: Evio – Fast event-loop networking for Go
#65Earlier quoted context omitted.
Patrick, on the 2.6+ Linux kernels, is there a significant difference between threads and processes? It seems like both threads and processes are created via clone and the only difference is memory access? I often hear "context switching between threads is cheaper" but pthreads still have their own PID and everything, so is this really the case? Is there really much advantage to pthreads over the way PostgreSQL does…
The significance of the distinction depends entirely on the use case. Yes, they’re both created with clone, but with different levels of sharing. A pthread will share the virtual address space of its parent, which makes shared memory simple to implement; use the same pointer and you’re done. CoW is not “sharing” really, because you can’t communicate over it, it just saves some creation overhead. With CoW, technically…
Indeed.
> Context switches are usually cheaper when you don’t need to throw out the old virtual address space (and invalidate the Translation Lookaside Buffer). Pthreads share virtual address space, so there is no need to flush the TLB.
I believe the cost of that has been reduced somewhat due to tagged TLBs on modern hardware.
> In a use case like Postgres, you don’t necessarily need to optimise for context switches. If you have a lot of concurrent connections, each of which has one process, then you’ll only hit limits with context switching overhead if very few of those connections are fighting over any locks or spending much time in IO at all. This is atypical, so usually those other factors hit you first.
Yea. There's a number of limitations in postgres due to the process model, but they're imo not TLB / context switch related. The biggest issue is that dynamically sharing memory between processes is harder, because there's no guarantee that it's possible for all post-fork memory allocations can portably be put at the same virtual addresses. Which then makes it more complicated to have shared datastructures, because you need to use relative pointers and such. That's not a problem for the main buffer pool etc, which is allocated when postgres is started, but it is problematic e.g. for memory shared between multiple processes working on the same query (say the memory for a shared hashtable in a hashjoin).
Re: Evio – Fast event-loop networking for Go
#66Earlier quoted context omitted.
The significance of the distinction depends entirely on the use case. Yes, they’re both created with clone, but with different levels of sharing. A pthread will share the virtual address space of its parent, which makes shared memory simple to implement; use the same pointer and you’re done. CoW is not “sharing” really, because you can’t communicate over it, it just saves some creation overhead. With CoW, technically…
> The significance of the distinction depends entirely on the use case. Indeed. > Context switches are usually cheaper when you don’t need to throw out the old virtual address space (and invalidate the Translation Lookaside Buffer). Pthreads share virtual address space, so there is no need to flush the TLB. I believe the cost of that has been reduced somewhat due to tagged TLBs on modern hardware. > In a use case lik…
I don't think this qualifies as a performance overhead, though, beyond the odd isub.
Re: Evio – Fast event-loop networking for Go
#67Earlier quoted context omitted.
> The significance of the distinction depends entirely on the use case. Indeed. > Context switches are usually cheaper when you don’t need to throw out the old virtual address space (and invalidate the Translation Lookaside Buffer). Pthreads share virtual address space, so there is no need to flush the TLB. I believe the cost of that has been reduced somewhat due to tagged TLBs on modern hardware. > In a use case lik…
> you need to use relative pointers and such I don't think this qualifies as a performance overhead, though, beyond the odd isub.
> I don't think this qualifies as a performance overhead, though, beyond the odd isub.
It ends up as one. The reason is less the additional instruction(s), but that you actually need to ferry arround additional data. In common scenarios you'll end up with a number of mappings shared between processes, so you can't just assume a single base address per-process. Instead you've to associate the specific mapping with relative pointers, and that does add to overhead. Both programming wise and runtime efficiency wise.