10 ms·
The root of the eventloop issue is not Node-specific. The real underlying issue here is that one CPU core is given too much work while others are more or less i
by jonpress 11y ago
The root of the eventloop issue is not Node-specific. The real underlying issue here is that one CPU core is given too much work while others are more or less idle. Offloading some of the work to another process naturally solves this issue - It doesn't really matter that this other process is a Go program or a Node.js one - Both approaches would have solved the problem. Attributing credit to Go itself for solving the issue is disingenuous.
If you ran Go as a single thread, you would also run into similar issues. The main advantage of Go is that it makes it easier to parallelize your code thanks to goroutines and channels (a single source file can encapsulate the logic of multiple concurrent processes).
That said, I find that this 'ease of concurrency' makes Go code less readable. In Node.js, it's really easy to identify process boundaries since the child_process module forces you to put code into different files and communicate via loosely coupled IPC channels.
Most of the Node.js vs Go arguments are weak. It's surprising that Node.js is still outpacing Go in popularity in spite of all this slander.
- mjburgess 11y ago> If you ran Go as a single thread, you would also run into similar issues. Yes, if you hobbled yourself, you would be hobbled. The inability to do concurrency properly is not a feature, it's a missing feature. The whole point of node was to be a node.
- Rapzid 11y agoI'm also unsure about this comment. It reads to me as "The main advantage of Go is.. that it makes it really easy to not have this problem." The OP talks about single core being an issue. It is not for Go due to the cooperative goroutine scheduling and function call pre-empting. You can still shoot yourself in the foot, but it's really easy to create an escape hatch by just making a function call or occasionally yielding to the scheduler...
- wpietri 11y ago> really easy to create an escape hatch by just making a function call or occasionally yielding to the scheduler... Having dealt with cooperative multitasking back in the dark ages, I definitely don't believe it is easy. With proper threads, you just write your code in a straightforward manner. With cooperative multitasking, you now have to be continuously imagining performance and sprinkling in otherwise useless calls every time you think something might take a while. When you get that wrong, which will be a fair bit, you have to go back and re-sprinkle. And then when the character of your input changes, you get to re-sprinkle again. I was ok with it in the dark ages; there wasn't an alternative given the hardware of the time. But now? Even watches are multi-core. I want to use languages that make parallelization easy.
- Rapzid 11y agoMeh, it really doesn't come up that often. Every method call is an opportunity for the scheduler to run, not just specific ones. I find it is very rare indeed for a significant amount of work to be done without making method calls. Go also uses threads and makes parallel programming easy.. For me anyway.
- wpietri 11y agoAh, I didn't realize that it happened at every method call. That seems more manageable. Thanks.
- pjmlp 11y ago> It's surprising that Node.js is still outpacing Go in popularity in spite of all this slander. From the perspective of a JVM/.NET/C++ developer I find surprising that Node.js got adopted at all in the server space.
- aikah 11y agowhy? PHP/ruby/python are successful too in the server space. Javascript,especially ES6, isn't worse than the formers. Devs should know by now that the dumbest tool that is good enough has good chances of being successful today. All these tech won't replace enterprise techs, but enterprise dev is a tiny percentage of all devs outthere.
- zerr 11y agoAlso, language-wise, TypeScript seems much more interesting than Go.
- pjmlp 11y ago> PHP/ruby/python are successful too in the server space. Again, from the perspective of someone that worked in a startup using TCL for server applications, I also don't get it. Other than being attractive to developers without formal education, and after a certain scale it becomes too costly to re-write. The work we developed at that company teached me never to use a technology stack without a JIT or AOT compiler for production code. The amount of money that Facebook has poured into PHP AOT compiler and now JIT is a proof of it, because it is just cheaper to improve the stack than re-write the code.
- awinder 11y agoThat's really all about how you structure things. If you're building small, distributed, API-oriented applications -- it's really very easy to re-write your infrastructure. If you're building large monolithic applications, with in-band communication only, you're right, it is pretty tough. The "formal education" piece is a little rough though. Count me among the developers working with Node.JS and a university degree.
- nemothekid 11y ago>Most of the Node.js vs Go arguments are weak. It's surprising that Node.js is still outpacing Go in popularity in spite of all this slander. Thats a rather defensive position for node in what is a very rare use case for the language. It's unsurprising Node.js is still outpacing Go, given the large number of JS developers and the fact that Go is pretty much worthless for hosting front end web applications (you won't find your favorite asset pipeline in Go). Its not surprising at all that they switched to a different language for data processing & pipelines, and its still somewhat surprising as that they chose Go, given that most teams in a situation like this would switch to the even more popular JVM/Spark/Storm/Kafka stack. Finally, your statement that The real underlying issue here is that one CPU core is given too much work while others are more or less idle. isn't accurate - the issue is one thread was has too much work - no modern OS built in the last 20 years would allow a single process to hog all the CPU time unless you explicitly turned off the kernel's scheduling. The root of the eventloop issue, is eventloop specific and its even more Node-specific since the event loop is pretty much the only way to achieve concurrency in node. Other languages (like Go and Java) at least have options for other models of concurrency. Consider the following - what if both processes got tied up? Do you just start another process? Would it feasible or wise to run 1000 processes (no it wont)? However this is a problem that you won't come across in Go by using goroutines and taking advantage of its scheduler, as you can easily run 1000s of goroutines performantly. That said - this is a rather narrow use case to make the judgement that one language is better than the other - its just the case that Go is likely better suited for these kind of services.
- EGreg 11y agoEvery language requires you to be careful. C makes you do array out of bounds checks. Javascript makes you worry about tying up your event loop with eg massive string processing. Just get a friggin asynchronous JSON parser if you're running it on untrusted client input (ie any client input). It's not that hard. Maybe node should provide a "tainted" feature for modules to mark variables that are "untrusted" and provide some warnings when functions like JSON.parse are run on them. The upside of JS is massive - easier to reason about control flow than threads, and much easier to build something much FASTER and efficient than threads.
- aikah 11y ago> If you ran Go as a single thread, you would also run into similar issues. Err no you wouldn't,you don't have to deal with interprocess communication when you deal with Go routines, you share memory between goroutines ie , true concurrency where as in node you'd fork some stuff, serialize data between processes and message with redis to make sure everything is notified something happen. Node isn't concurrent. Go is. That's why you read all these blog posts about "how I moved from Nodejs to Go(or rust)" and that's why you'll read more of them.
- wpietri 11y ago> In Node.js, it's really easy to identify process boundaries since the child_process module forces you to put code into different files and communicate via loosely coupled IPC channels. I find that approach troubling. Process boundaries are expensive, because you have to serialize and everything each time you cross a boundary. I also haven't used Go, but I think you can get great clarity with something like Akka's Actor model. And to do it you don't have to pay a large serialization tax until you move particular actors to other machines.
- jonpress 11y agoYes, socket/pipe-based IPC is more expensive than shared memory up to a point, but it's more scalable since you don't have to deal with locking (mutexes, semaphores) and the limits this imposes.
- zaphar 11y agoThere is scaling and then there is scaling. Sometimes you want to scale up to the box you are on and the most efficient way to do that is to use threads in a single process. When you hit the limits of a single machine then it's time to start scaling out to multitple machines. You are right that then you have to start paying the communication/serialization costs and in return you get much greater scale. However you don't have to start paying that cost until scale in that direction. You can get quite a lot out of multicore machine these days without having to pay serialization costs if you use threads. Many times the serialization costs aren't worth the benefit unless you are getting a whole other box with another 32+ cores out of the deal. Paying it before you get that benefit isn't efficient engineering. And for some people choosing a language or framework that forces them to pay that cost before it's necessary is a bad idea.
- wpietri 11y agoIf you don't want to deal with locking but are willing to pay extra memory cost, then you can just duplicate the data. A re/de-serialization step is a much more expensive way to do that.
- falcolas 11y ago> The main advantage of Go is that it makes it easier to parallelize your code thanks to goroutines and channels Well, that and Go is not bounded by a VM (jit or no), and will simply be faster than JavaScript, given the exact same logic. Don't discount the cost of running on a VM, and all of the abstractions which are thrown on top of plain JavaScript to help manage the callback complexity.
- Roboprog 11y agoGiven enough money, a JIT can be made arbitrarily fast, it seems (e.g. - JVM, LLVM bitcode interpreter) Given time, don't assume any particular language implementation will always be faster. Go might only run faster than Javascript on the odd years, depending on corporate budgets for compiler / VM tuning the previous year.
- falcolas 11y agoThe JVM has received a lot of money and attention over the years, yet still falls quite short of its direct compiled competitors in almost any benchmark. The threshold for "enough" when it comes to improving a JIT is still arbitrarily high.