为什么Node.JS中的函数和回调没有阻塞? [英] Why is a function and a callback non-blocking in Node.JS?

查看:108
本文介绍了为什么Node.JS中的函数和回调没有阻塞?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对Node的新手理解是,如果我重新编写同步代码或内联代码以利用函数/回调,则可以确保我的代码是非阻塞的.我很好奇这在事件堆栈方面的工作原理.来自这里的简单示例:不理解回调-Stackoverflow 会阻塞:

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 curious how this works in terms of the event stack. The simple example from here: Don't understand the callback - Stackoverflow is that this will block:

var post = db.query("select * from posts where id = 1");
doSomethingWithPost(post)
doSomethingElse();

这不会:

callback = function(post){
doSomethingWithPost(post)
}

db.query("select * from posts where id = 1",callback);
doSomethingElse();

好的,我知道我们应该使用回调.但是就事件堆栈而言,这为何起作用? Javascript是单线程的.在第一个示例行中,它使用了昂贵且阻塞的I/O操作.第1行完成之前,第2行无法执行.这是因为第2行需要来自第1行的信息吗?还是因为I/O事件从根本上阻止了操作,这意味着它们抓住了控制权,直到完成才将其交还给我们...

Ok, I understand that we should use callbacks. But in terms of the event stack why does this work? Javascript is single threaded.. in the first example line one makes use of an expensive and blocking I/O operation. Line 2 can't execute till line one is done. Is this because line 2 requires information from line 1? 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...

在第二个示例中,昂贵的I/O已移至一个函数中,而我们现在有了一个回调函数.当然,只有在I/O完成后才能执行回调.这不会改变.因此,执行一次和两次执行之间花费的时间差必须主要是如果第二个请求到达服务器时将发生的情况.

In the second example the expensive I/O has been moved into a function, and we now have a callback function. Certainly the callback can't execute until the I/O is done.. This would not change. So the difference in amount of time it takes to execute between one and two must primarily be what would happen if a second request hit the server.

如果第二个请求命中了示例1,则由于阻塞操作,直到请求1完成,它才能够处理.但是在示例2中,将操作移入函数会自动产生子进程或充当子进程.多线程的?如果Javscript是单线程的,除非采取某种并行处理方式,否则这仍然会带来问题.如果我们使用非阻塞技术(例如子进程等),那么函数/回调是否只能保证是非阻塞的.

If a second request hit example one, it wouldn't be able to process until request 1 was done because of the blocking operation.. but in the example two.. does moving operations into functions automatically spawn child processes or act as multi-threaded? If Javscript is single threaded this would still pose a problem unless there was some way of doing parallel processing.. Does a function / callback only guarantee to be non-blocking IF we make use of non-blocking techniques like child processes, etc...

推荐答案

假设您正在一家面包店操作收银机.您可以按顺序和同步地处理客户,如下所示:

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

  1. 接订单
  2. 告诉面包师烤面包
  3. 等到面包烤好
  4. 充值钱
  5. 送面包
  6. GOTO 1-下一位客户

那将非常慢.现在,试着依次接订单,但异步处理客户:

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

  1. 接订单
  2. 告诉面包师烤面包,吃完后通知您.收到通知时:
  1. Take order
  2. Tell baker to bake the bread, and notify you when finished. When notified:
  1. 充值钱
  2. 送面包

  • GOTO 1-下一位客户
  • 更新:我重构了上面的内容,因此它更类似于回调.您(收银员)向面包师下达订单后将立即执行第3步.当面包师通知您面包已经准备好时,您将进入步骤2.1.

    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.

    您和您的朋友是两个并行运行的单线程事件循环.这类似于两个接受请求的node.js进程.您无需执行任何复杂的操作即可并行化此操作,只需再运行一个事件循环即可.

    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.

    现在,node.js还为IO运行内部线程池.这是从您这里抽象出来的:要继续进行面包店的比喻,假设您有一个面包店池"的面包店-对您来说,站在收银机上,您不必了解这一点.您只需给他们下订单(一块酸面包"),然后在收到通知后就下达该订单.但是面包师们正在他们自己的面包师池"中并行烘烤面包.

    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".

    这篇关于为什么Node.JS中的函数和回调没有阻塞?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆