4 ms·
Doing synchronious is much clearer and easier, most of the async patterns (like yield/await and promises) really just try to simulate a sync paradigm. But ther
by Illniyar 10y ago
Doing synchronious is much clearer and easier, most of the async patterns (like yield/await and promises) really just try to simulate a sync paradigm.
But there is one great reason why node's async first mentality is superior- when you want to do async in node, you don't have to worry that some library you are using is going to lock up your thread.
In any other language, you have to painstaikingly make sure everything you use isn't doing sync, or try and monkeypatch all io operations (python has something like that).
Frankly, for me, when I'm dealing with webservers I find myself needing to use async quite a lot.
- icebraining 10y agoIn any other language No; for example, in Go, every time the code does IO, the scheduler will re-assign another goroutine, and they asynchronously get back to the other when the IO finishes. It doesn't need any special support by the library.
- Illniyar 10y agoThat sounds like an implicit async/await, which sounds rather awesome. I haven't really gotten around to trying Go yet, but there are definitely great things going on there.
- zigzigzag 10y agoIt's just green threading, which has been around for a long time. You can run millions of threads on a single machine with modern Linux kernels if you either have lots of memory or simply minimize your stack sizes and usage. The kernel doesn't care much. You don't really need any special language features. The main reason fibers/green threads/goroutines/etc have become popular lately is that common language runtimes and standard libraries don't resize thread stacks on the fly and tend to like very deep call stacks, so minimising your memory usage can be rather hard.
- soulbadguy 10y ago> he main reason fibers/green threads/goroutines/etc have become popular lately is that common language runtimes and standard libraries don't resize thread stacks on the fly and tend to like very deep call stacks, so minimising your memory usage can be rather hard. Green-thread, coroutine have been around for a long time, the recent popular is probably due to increase prevalence of people trying to solve the C10K problem. Green thread, are more efficient both in term of memory consumption and context switching than kernel thread (even more so with compiler support). The linux kernel might be able to handle millions of threads, but thruth is one can do it much more efficiently in userland
- epidemian 10y ago> when you want to do async in node, you don't have to worry that some library you are using is going to lock up your thread. > In any other language, you have to painstaikingly make sure everything you use isn't doing sync I haven't found that to be the case TBH. In most other languages i've used i don't have to worry about foo() being syncronous or not. I can assume that. In other words, after the control returns from the foo() call, i can assume that what foo() is supposed to do has been completed. In the case that foo() needs to do some IO operation, i can usually rely on it doing a syscall that will block the thread and put it to sleep, instead of doing something nefarious like busy waiting. And that's it. The current thread will sleep while the IO operation in foo() completes, and the OS (or VM if we're talking green threads) will switch the CPU to do something else in the main time. And if it's a web server we're talking about, that something else may be another web server thread, serving a different request. Yay, preemptive multitasking! In the case of node, you do very much have to worry about a function call being synchronous or asynchronous, as it defines the way it has to be called. In the former case, it can be called "normally": let a = foo() // use `a` In the async case, some code gymnastics need to be involved: // Either callbacks: foo(a => { // use `a` }) // Or promises: foo().then(a => { // use `a` }) // Or promises + await syntax: let a = await foo() It may not seem a big problem at first, especially if using the `await` syntax is an option. But to me the biggest problem of this technique is that the "async-ness" of a function cannot be abstracted away. If a function `foo` that has always been synchronous, and that is used in several places, needs to be changed, and this change implies `foo` calling an async function `bar`, then `foo` will need to become async too, and all the places where `foo` is called will need to be changed. Even though this internal `bar` async call was an implementation detail of `foo` that shouldn't have concerned `foo` callers. And this propagates all the way up: if any of the places where `foo` was called was, in turn, a synchronous function too, then that function will also need to be refactored into an async one, and so on and so forth. And that's basically why i find node's distinction between sync and async functions so frustrating :( PS: Cooperative multitasking does not imply this weird syntax complexity of having two different kinds of function calls that cannot be freely intermixed. For instance, Eralng "processes" use cooperative multitasking, but the "yields" are managed implicitly by the VM, so you don't need to explicitly yield control of the current thread to let other stuff run concurrently.
- Mister_Snuggles 10y ago> Doing synchronious is much clearer and easier, most of the async patterns (like yield/await and promises) really just try to simulate a sync paradigm. I'm currently working on some lighting (DMX-based theatre lighting) software and the ability to have my 'effects' written in a sequential manner by using 'yield' is actually incredible. It's simplified my code a huge amount and made it a lot easier to reason about. There is a function called every frame, which then calls each effect. Since each effect is a Python generator function, it can be written sequentially and just has to yield whenever the frame is computed.