5 ms·
Creating millions of coroutines or "goroutines" isn't really interesting by itself. I believe the real questions for me are: 1. is Go scheduler better than Lin
by the_other_guy 8y ago
Creating millions of coroutines or "goroutines" isn't really interesting by itself. I believe the real questions for me are:
1. is Go scheduler better than Linux scheduler if you have a thousand concurrent goroutines or threads?
2. is really creating goroutines that much faster than creating a native thread?
3. are gorutines relevant for long lived and computationally intensive tasks or just for short lived I/O task?
4. What is the performance of using channels between goroutines compared to native threads?
tbh, I have read several of respected articles that criticize Golang goroutines in terms of performance and I am not really sure that Golang's only virtue imho which is simple concurrency is performant at all
- exabrial 8y agoI guess it's interesting if it makes the programming model easier, but with similar or better performance than normal threads.
- the_other_guy 8y agoif it's about simplicity, then Javascript and Node are better at concurrency for me when it comes to I/O, Node is very performant too
- exabrial 8y agoNode is definitely not performant by any equal benchmark, but the async model does lend itself to simplicity in some cases in non-sequential workloads. But even then, it gets stomped by vert.x running on the jvm. I think the most valuable contribution is democratizing package management for SPAs as we move towards thick clients again.
- weberc2 8y agoI find goroutines and channels much easier to work with than promises, callbacks, or async/await, and the former can parallelize computation as well. Not to mention that Go is typically faster than Node in single-threaded execution.
- mikekchar 8y agoYou can easily implement channels in ES6. I've done it and my implementation is probably 40-50 lines of code. You can then use async/await to simulate go routines. It's actually a bit nicer than go because of the way async coordinates with promises. You can more easily synchronise the routines (for example in situations where you might need a wait group in go). I keep expecting someone to write one and put it up on NPM (I haven't looked recently, though). Perhaps I should clean up my and stick it up there. It provides a very nice abstraction of continuations. I did it merely as kata to show that continuations do not require concurrency.
- deleted 8y ago[deleted]
- spiralx 8y agoI've read a few articles on implementing CSP in JavaScript, and there are definitely some packages available, e.g. https://github.com/olahol/node-csp https://github.com/olahol/node-csp https://github.com/ubolonton/js-csp https://github.com/ubolonton/js-csp https://github.com/gozala/channel https://github.com/gozala/channel
- weberc2 8y agoThese 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.
- ridiculous_fish 8y agoHow 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.
- denormalfloat 8y agoYes, 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.
- denormalfloat 8y agoGo's scheduler is not preemptive, which means that sometimes Goroutines can hog the processor. If loops don't contain function calls, or allocate memory, or other preemption points, they can prevent other goroutines from running. A simple example is: package main func main() { go println("I ran") for {} } If you run with: GOMAXPROCS=1 go run main.go It will never print the statement. This doesn't come up frequently in practice, but Linux does not suffer from this case.
- devxpy 8y agoInteresting find.
- twtw 8y agoI heard Go got a preemptive scheduler recently. EDIT: https://github.com/golang/go/issues/24543 https://github.com/golang/go/issues/24543
- the_clarence 8y agoThis just happened to me. I wanted to run a goroutine and then not exit the program, so I ran an empty for loop and it didn’t work. Would a for{ continue } have work?
- deleted 8y ago[deleted]
- grose 8y agoYou can use select{} to block forever and yield the goroutine.
- the_clarence 8y agoYield?
- majewsky 8y ago`for { continue }` is semantically equivalent to `for {}` since the closing bracket of the loop block implies a `continue`. As a sibling correctly notes, `select {}` is what you want to do instead. You need to do something that can block the goroutine in such a way that control returns to the scheduler. Selecting is one of those ways.
- graycoder 8y agoYes Yes Both Wat Are you asking to compare mutexes and channels? The article goes through multiple reasons why the go scheduler has more information about how something should execute than the Linux kernel. Reread and then maybe rephrase?
- jonathanstrange 8y agoIt seems to me that Green threads exist primarily for convenience. They are definitely not more performant than native threads with a work-stealing approach (producer - consumer pattern) that is tuned to the number of cores available. How could they be more performant? Even the simplest switching adds some cost, from a performance perspective it would never make sense to run thousands of threads on 8 cores, whether they are scheduled by the OS or by the language implementation. So to answer your 3rd question: short lived I/O tasks.