2

Have read tons of articles and docs, however this topic still not clear enough to me. Quote from one answer https://stackoverflow.com/a/46004461/630169:

As long as the code contained inside the async/await is non-blocking it won't block, for example, db calls, network calls, filesystem calls.

But if the code contained inside async/await is blocking, then it will block the entire Node.js process, for example, infinite loops, CPU intensive tasks like image processing, etc.

However, Understanding the node.js event loop says:

Of course, on the backend, there are threads and processes for DB access and process execution.

In C# it is enough to write function marked with async and call with await so .Net puts it in another thread. However, it confused me things organized differently in Node.js and async/await function still could block the main thread.

So the question is: how to write (organize) arbitrary async/await function in node.js to be sure it will run asynchronously in separate thread or process? Is there good code example? Some npm module? Also good to have it not much trickier than C# variant. Thanks!

Some function example to made it non-blocking, for example, if I want synchronous DB call to make asynchronous (non-blocking):

var Database = require('better-sqlite3');

var db = new Database('./my_db.sqlite');

async function DBRequest() {
    var row = db.prepare("SELECT * FROM table");
    return row;
};

Note: better-sqlite3 — synchronous module.

Aleksey Kontsevich
  • 4,671
  • 4
  • 46
  • 101
  • 4
    *"In C# it is enough to write function marked with async and call with await so .Net puts it in another thread."*. This is not how async/await works and is your fundamental misunderstanding - async and threading are different concepts and while it is *possible* to wait on background threads using async/await it is *not* the primary use case. – Ant P Oct 31 '17 at 10:25
  • node.js is single-threaded. You can write long-running blocking code in such a way that it can yield execution time to other functions -- there are definitely techniques for that -- but blocking code is blocking code. – TKoL Oct 31 '17 at 10:28
  • @TKoL need good example to make blocking code - non-blocking. – Aleksey Kontsevich Oct 31 '17 at 10:29
  • I'm not going to give you a tangible example, but I can explain to you how to do it. Let's say you have an array of 100 items that you want to process, and each item will take 0.5 seconds (of blocking time) to process -- you want to write a function to process them all, but you don't want it to block for 50 seconds. What you would do is write your function to process one element of the array, and then write a recursive function to process the next item in the array after a `setTimeout` delay. That's one technique. – TKoL Oct 31 '17 at 10:31
  • @TKoL not work for all cases. Need more universal approach. For example, I have synchronous DB library call and want to make function which uses it `async`. – Aleksey Kontsevich Oct 31 '17 at 10:52
  • @AlekseyKontsevich you don't "make blocking code non-blocking." Blocking code is blocking code. In multithreaded languages you *work around* this with threads. In single-threaded languages you don't. You could offload the work to another process perhaps. There is no "general purpose" solution to this problem. – Ant P Oct 31 '17 at 10:59
  • @AntP bad if so, cause node.js solves this creating threads and processes for IO operations. – Aleksey Kontsevich Oct 31 '17 at 11:01
  • @AlekseyKontsevich I'm not sure what point you're trying to make, sorry. – Ant P Oct 31 '17 at 11:03

3 Answers3

0

Well here's some example code. Decided it was a worthwhile exercise to provide it.

You can write long-running blocking code in such a way that it can yield execution time to other functions

var array = new Array(100);
function processNext(){
    if (array.length === 0) return;
    var item = array.shift(); // gets first item from array and removes it.
    process(item); // 0.5 seconds of blocking time
    setTimeout(processNext ,500); // wait 0.5 seconds and then process the next one
    // during this waiting time, other code will run on your server.
}

processNext();

Admittedly I'm a novice and this may be a very bad idea for reasons I don't know about.

TKoL
  • 13,158
  • 3
  • 39
  • 73
  • Code example added in the question: how to convert it to `async` (non-blocking)? – Aleksey Kontsevich Oct 31 '17 at 11:00
  • most sql database interactions are almost certainly already non-blocking. I use an sql node library and most of its methods return promises. – TKoL Oct 31 '17 at 11:16
  • You're being very unclear about what it is specifically you want. It doesn't seem like you understand what is and isn't non-blocking, or the situations where you would need that. Provide some specific code that is blocking, and I can potentially show you how to use the technique above to make it so that *pieces* of it run at a time, but yield to other parts of your code between pieces. – TKoL Oct 31 '17 at 11:18
  • Question is edited, example is there, mentioned library is blocking. – Aleksey Kontsevich Oct 31 '17 at 11:25
  • Sorry, you're saying that the single line of code, `db.prepare("SELECT * FROM table");`, is blocking? If that's what you're saying then... it's almost certainly not blocking for long enough to worry about, and if it is, there's nothing you can do apart from maybe creating a timeout condition. – TKoL Oct 31 '17 at 11:31
0

You're really at the mercy of the library your using here - if the code is synchronous and not I/O bound then there's really not much else you can do within your Node process to make it asynchronous.

Your only real alternative is to move that code into it's own process which consequently makes it I/O bound, that way your app can wait on it and not block it's own thread.

James
  • 80,725
  • 18
  • 167
  • 237
  • That library is just and example. Just asking about a way to make ANY function `async` and non-blocking. Seems in JS `async/await` does nothing. It only simplifies promises usage. If there is no promise in underlying function, then you can't make it `async` and non-blocking. – Aleksey Kontsevich Oct 31 '17 at 12:11
  • @AlekseyKontsevich what your asking isn't possible with Node - any code that executes within your Node process will take the thread _at some point_. If the code you call is blocking then ultimately it will block the thread until it's finished. Where Node differs from multi-threaded environments (like C# you mentioned) is they can spawn new threads and offload the work, Node can't do this as it's deliberately single-threaded to avoid the complexity of thread management. If you feel you need threading then you're probably using the wrong tool for the job.... – James Oct 31 '17 at 12:55
  • @AlekseyKontsevich it doesn't "do nothing," it does the same thing as async/await in C#, which is allow you to represent asynchronous processes with sync-like constructs. It doesn't let you "make blocking code non-blocking" in either language, because that does not make sense. – Ant P Oct 31 '17 at 16:39
  • @AntP IIRC C# async/await is different in that it _can_ offload synchronous code onto a worker thread (at least the `await` keyword can), whereas with Node, it is just effectively syntactic sugar. Your point still stands though, and I've tried to re-emphasise the same point, there is no magic code that can turn blocking code into non-blocking.... – James Oct 31 '17 at 17:09
0

My interest was not for nothing - similar questions people asked before me, as well as on stackoverflow (and here):

But what's with longish, CPU-bound tasks?

How do you avoid blocking the event loop, when the task is at hand is not I / O bound, and lasts more than a few fractions of a millisecond? You simply can not, because there's no way ... well, there was not before threads_a_gogo.

and to solve them they have already created a bunch of modules, and some, such as threads, work both in the browser and in Node.js:

Good if someone could attach async/await to them or provide good example - that would be nice.

By the way, here's a comrade tests driven on Threads à gogo - results with threads is 40x faster than with Cluster. So single threaded idea of Node.js does not always work well.

Aleksey Kontsevich
  • 4,671
  • 4
  • 46
  • 101
  • Not sure what your answer adds that everyone in this thread hasn't already pointed out.... – James Nov 01 '17 at 21:19
  • Pretty much boils down to the point again of if you are trying to build an app that relies heavily on multi-threading, Node probably isn't the right tool. – James Nov 01 '17 at 22:12