http://golang.org/doc/go_faq.html#goroutines
When they say "system resources" they mean stack space. It's limited in 32-bit because a stack large enough to be useful takes up too many virtual address space. For instance an 8 MiB stack takes up 1/512 of the 32-bit address space so you can only have max 512 threads, but in 64-bit you can have 33 million (current CPUs limited to 2^48 address space)
So they segment the stack in Google Go to get more than some small number of threads. Even though Linux (edit: the kernel) only uses 4k or 8k per thread some OSes have severe limits, so they compound the segmented stack problem (making C interop slow and cumbersome) with userspace threading (M:N). A collection of links why that's a bad idea:
http://www.kegel.com/c10k.html#1:1
Eventually they'll concede that this wasn't a good idea, but I wouldn't bet on when.
Linux doesn't use 4k or 8k stack per thread, pthreads default on Linux is 2MB. The only thing that's 4kB or 8kB is the kernel stack which doesn't have anything to do with this (the kernel stack 12kB or 24kB on Windows). You might have heard about this "grow stack on demand" thing, but every OS does it, not only Linux and it's about growing the committed memory, the virtual memory used by a stack is fixed at thread creation.
Calling C code is very fast and it's trivial to do from Go, http://golang.org/doc/articles/c_go_cgo.html. Segmented stacks are available in some C implementations as well.
It's not Google Go, it's simply Go, there's not a single Google reference on the page and that's intentional. Looking at your previous posts I see you have an obsession with Google.
In short, you have absolutely no idea about what you are talking about and you spread malignant misinformation.
Not that anyone knew of the older Go before the whole naming debacle, but it may not just be anti-Google trolling to refer to it as Google Go.
/devils advocate hat off.
I think you should read the M:N scheduling links. I'll leave it at that.
> Calling C code is very fast and it's trivial to do from Go, http://golang.org/doc/articles/c_go_cgo.html. Segmented stacks are available in some C implementations as well.
http://golang.org/src/pkg/runtime/cgocall.c
Read the comment at the top. Hardly trivial.
> It's not Google Go, it's simply Go, there's not a single Google reference on the page and that's intentional. Looking at your previous posts I see you have an obsession with Google. ... In short, you have absolutely no idea about what you are talking about and you spread malignant misinformation.
Shoot the messenger. Maybe I post from a different account when I am critical of Microsoft, or Apple. Why would that matter to you?
Of the links in that list, 2 worked for me, and both were from 2002. Not exactly up to date information. Also, Erlang, does something similar w.r.t. to multiplexing multiple processes onto fewer threads, so Go isn't exactly alone in this regard. Even Twisted, and Node use a weaker form of this, where everything runs on one thread.
> Read the comment at the top. Hardly trivial.
First, the comment's meant for language implementors. You don't need to read this comment to be able to do C interop in Go. Second, this isn't even that complicated... did you imagine C interop with other languages is done in a nice, simple way? Any language needs a way to translate calling conventions from the source to the destination and back when doing interop.
And, yes, please stop calling it Google Go. People hardly ever say Microsoft C# or Sun Java or Apple Objective C, or Ericcson Erlang, or Netscape Javascript...
The links for Ingo and Ulrich worked, these are enough of an indictment of M:N threading. What's changed in the last decade? OS gurus tried M:N threading and it failed. Java tried 'green threads' and it failed, and now Google Go devs are trying the same thing. Guess what's going to happen?
> Also, Erlang, does something similar w.r.t. to multiplexing multiple processes onto fewer threads
Erlang was written in Prolog and the desktop VM was single-process until several years ago. That's not a good example implementation to base a design on for a new language. Meanwhile the good things like separate heap/gc per 'thread' weren't copied. /forehead
> did you imagine C interop with other languages is done in a nice, simple way? Any language needs a way to translate calling conventions from the source to the destination and back when doing interop.
I don't think I know of another language that locks another thread, transfers control to it, and then finally calls the C function. That's crazy talk -- why they say "down the rabbit whole" in that comment. Most languages do some type checking (for instance error on passing a BigInteger > uint32_t to a function taking uint32_t) and marshall the arguments then call the C function. Maybe they need to pin an object or convert it to a C-friendly form (make a struct that describes properties of the object). But yeah in general the C interop is very simple in most languages.
> And, yes, please stop calling it Google Go. People hardly ever say Microsoft C# or Sun Java or Apple Objective C, or Ericcson Erlang, or Netscape Javascript...
I don't say "Google Dart" because Dart isn't an unsearchable, ambiguous name for a programming language. I do say "Apple Blocks" because 'blocks' is unsearchable in the context of programming languages. You can't blame me for Google choosing a terrible name.
Edit: What do you think it says to neutral readers when facts, reasons, links are downvoted?
Uh...the need for highly scalable web servers handling tens/hundreds of thousands of lightweight, I/O bound, concurrent requests?
The nature of the problems we are trying to solve, and the hardware we are solving them on.
> But yeah in general the C interop is very simple in most languages.
You're not taking into account the fact that the C code cannot be allowed to block the main loop of the program; as is true in any event driven system. Yea, other programming languages might not have to deal with concurrency issues, either by ignoring threading, giving up on an asynchronous system, or giving up on C interop; none of which seem like a worthwhile sacrifice. What is your problem with this implementation technique? It's performant in practice, and its not in your face when actually writing code. This is not complexity you have to worry about. It happens "behind the scenes" as it were.
Go might be challenging to search for, but you're not writing search queries, you're writing posts about programming. It's pretty unambiguous as far as I'm concerned.
And fyi, I've never downvoted you. I think with the increasingly desperate tone in your writing, its not hard for people to realize that you're just hating on Go, and at least the responses to your misinformation are educational, and often interesting.
The increase in cores, NUMA now being pervasively inescapable, and context switching becoming cheaper, actually makes this problem worse for M:N threading.
I don't have a problem with Go using M:N threading, but we must also be honest that something is being given up in order to gain something else; Go has a nicer programming model, but its performance envelope shrinks and becomes less predictable.
Let me answer some of your points more specifically: NUMA is a concern, but with some work on the schedular to give goroutines slight affinity for threads, this can be largely mitigated. This could be as simple as a scheduler policy like `take the first queued goroutine that previously executed on this thread, looking upto 5 into the queue, otherwise take the first one` instead of `always take the first one`. The difficulty with this strategy is you could experience starvation of goroutines, and there are a ton of other complexities, which is why the current scheduler is so simple. I believe this will get better...
Context switching isn't the issue with threaded implementations of servers. Writing a server with a thread per connection is a bad idea because of the memory requirements. 1000 connections will lead to gigabytes of memory in use.
I don't think Go's performance envelope has shrunk or become less predictable, IMO. I think what we've given up is control over what threads execute what goroutines, essentially, the NUMA argument above. This will hopefully get better with time.
Alas, it is, because there's no communication between the kernel scheduler and the user-space scheduler. The resulting interaction has non-intuitive results.
Here's an old paper about some of the measured consequences: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.50....
I get exasperated is because you guys rarely ever back up your claims. For instance, the response I get to what changed is 'things'. What things? Did synchronization between threads get 100x more expensive? Does unpredictable blocking like from page faults no longer happen? Are real time and consistent scheduling no longer important? What 'nature of problems' changed?
> You're not taking into account the fact that the C code cannot be allowed to block the main loop of the program; as is true in any event driven system.
Why can't the C code block? Because they do their own M:N threading and segmented stacks. Why do they do that? To run on 32-bit without complications. That's exactly the point I've been making.
Why in 2009+ care about a 32-bit implementation? Like I said originally, good question.
I think this bears emphasizing.
Slow language runtimes, like Erlang's beam.smp, can get away with using M:N threading because the overhead elsewhere is so high. However, once you're dealing with languages implementations which are reasonably performant, which includes Go, M:N threading has problems which suddenly surface above the waterline. This includes various inefficiencies due to two schedulers fighting each other, significantly reduced system observability, and bizarre runtime behaviour (again, due to two schedulers fighting each other). If the ability to understand and maximize performance matters, M:N threading is a disaster.
We've been down the M:N road before for efficient systems (Solaris, Linux, the *BSDs, and others). Those implementations -all- died. Now Go (and Rust, both amazingly and depressingly) have resurrected this. I can only hope that the programming abstraction niceties that Go takes advantage of are worth the performance tradeoff, because there is a definite tradeoff.
Also, is the incompatibility between Go and C just due to the segmented stacks in Go? What about function call conventions? Anything else?
My current guesses are: 1) Performance 2) The need to call assembly code easily
The runtime needs to break the abstractions Go provide, it needs to break Go's memory model, it needs to be aware of the garbage collector, it needs to be aware of stacks, stack growths and switch them, and it needs to do other things: http://research.swtch.com/goabstract.
C was chosen as the pragmatical choice, they could have done it all in assembly (various bits are written in assembly), but C is a portable assembler.