Why is a function and a callback non-blocking in Node.JS?

后端 未结 4 1758
你的背包
你的背包 2020-12-06 01:37

The novice understanding of Node is that if I re-write synchronous, or in-line code, to utilize functions / callbacks, I can ensure that my code is non-blocking. I\'m curio

相关标签:
4条回答
  • 2020-12-06 02:19

    IMPORTANT - The db.query() does not block the stack, as it is executed elsewhere.

    Example 1 blocks because line 2 needs information from line 1 and therefore has to wait until line 1 completes. Line 3 cannot be executed before line 2 as code in processed in order of line, and therefore line 2 blocks line 3 and any further lines.

    Example 2 is non-blocking as the callback function is not called to be executed until db.query is finished, therefore it does not block doSomethingElse() from being executed.

    0 讨论(0)
  • 2020-12-06 02:34

    The accepted answer is great, but I would like to add something purely related to nonblocking, specifically this part of the question:

    Or is it because I/O events are just fundamentally blocking operations meaning that they seize control and don't give it back until done...

    Asynchronous IO is possible even without a framework providing its own pool of IO worker threads. Indeed, it can be done without any multi-threading at all as long as the underlying (operating) system provides some mechanism to do non-blocking IO.

    Typically this boils down to a system call like POSIX's select (or Microsoft's version of the same), or more recent variations on the same idea like Linux's epoll.

    Hypothetically speaking, if we see a function like db.query in your example, and assuming we also know that the framework providing that function does not rely on any multi-threading, then it is usually safe to conclude that:

    • The framework keeps track of a global list of IO descriptors and callbacks associated with any non-blocking IO requests which were initiated, like your db.query call.
    • The framework has or relies on some sort of main application event loop. This could be anything from an old-school while(true) to something like libev
    • Somewhere in said main loop, select or a similar function will be used to check if any of those pending IO requests have finished yet.
    • When a finished IO request is found, its associated callback gets called, after which the main loop resumes.

    An SQL DB call like your db.query probably uses network socket IO and not file IO, but from your perspective as an application developer, socket and file descriptors are handled in nearly identical ways on many operating systems, and can both be passed to select on POSIX-likes anyway.

    This is usually how single-threaded, single-process server applications "juggle" multiple simultaneous connections.

    0 讨论(0)
  • 2020-12-06 02:35

    I'm not well at English, so I can't understand what you exactry mean. But I can say that 'multi thread' and 'asynchronous' are similar but different term. Even if single thread can peform as 'asynchronous'.

    This document is not for node(it's for a python asynchronous framework "twisted") but might be helpful for you.

    sorry for my poor English.

    0 讨论(0)
  • 2020-12-06 02:37

    Imagine you're operating the cash register in a bakery. You handle your customers sequentially and synchronously, like this:

    1. Take order
    2. Tell baker to bake the bread
    3. Wait until bread is baked
    4. Charge money
    5. Deliver bread
    6. GOTO 1 -- next customer

    That will be very slow. Now, try instead to take the orders sequentially, but handle your customers asynchronously:

    1. Take order
    2. Tell baker to bake the bread, and notify you when finished. When notified:
      1. Charge money
      2. Deliver bread
    3. GOTO 1 -- next customer

    UPDATE: I refactored the above, so it more closely resembles a callback. You, the cashier, will hit step 3 immediately after giving the order to the baker. You will hit step 2.1 when the baker notifies you that the bread is ready.

    In this manner, you will still deliver as much bread - you can only sell as much bread as your baker can bake. But you can deal with your customers in a more efficient manner, because instead of idly waiting for an order to come back, you start handling the next customer.

    Now, you could go all sorts of fancy on this, and charge the money upfront, and tell the customer to pick up the bread at the other end of the desk, or something like that. I think Starbucks are pretty "evented" in this way. The cashier takes the order, issues a number of requests for stuff, and tells the customer to wait until everything is standing in the pickup area. Super-efficient.

    Now, imagine that your friend starts operating another cash register. He follows your async example. You can handle more customers, even quicker! Note that the only thing you had to do was to put your friend there and give him your workflow.

    You and your friend are two single-threaded event loops running in parallel. This is analog to two node.js processes taking requests. You don't have to to anything complex to parallelize this, you just run one more event loop.

    So, no, "moving operations into functions" does not "automatically spawn child processes". They are more akin to alarms -- when this is finished, notify me and let me pick up at this point, "this point" being the code in your callback. But the callback will still be executed in the same process and the same thread.

    Now, node.js also operates an internal thread pool for IO. This is abstracted away from you: To continue the bakery analogy, let's say you have a "baker pool" of bakers -- to you, standing at the cash register, you don't have to know about this. You just give them the order ("one sourdough loaf") and deliver that order when you are notified that it's finished. But the bakers are baking their bread in parallel, in their own "baker pool".

    0 讨论(0)
提交回复
热议问题