单线程同步和异步混淆 [英] Single thread synchronous and asynchronous confusion

查看:87
本文介绍了单线程同步和异步混淆的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设makeBurger()将需要10秒

在同步程序中,

function serveBurger() {
   makeBurger();
   makeBurger();
   console.log("READY") // Assume takes 5 seconds to log. 
}

这将总共花费25秒来执行.

This will take a total of 25 seconds to execute.

因此,对于NodeJ,可以说我们制作了makeBurgerAsync()的异步版本,该过程也需要10秒钟.

So for NodeJs lets say we make an async version of makeBurgerAsync() which also takes 10 seconds.

function serveBurger() {
   makeBurgerAsync(function(count) {

   });
   makeBurgerAsync(function(count) {

   });  
   console.log("READY") // Assume takes 5 seconds to log. 
}

因为它是一个单线程.我很难想象在幕后到底发生了什么.

Since it is a single thread. I have troubling imagine what is really going on behind the scene.

  1. 因此可以肯定的是,当函数运行时,两个异步函数都将进入事件循环,并且console.log("READY")将立即执行.
  2. 但是,当执行console.log("READY")时,两个异步函数都没有真正完成工作吗?由于单线程占用了console.log 5秒钟.
  3. 在console.log完成之后. CPU将有时间在两个异步之间切换,以便每次可以运行每个功能的一部分.
  1. So for sure when the function run, both async functions will enter event loops and console.log("READY") will get executed straight away.
  2. But while console.log("READY") is executing, no work is really done for both async function right? Since single thread is hogging console.log for 5 seconds.
  3. After console.log is done. CPU will have time to switch between both async so that it can run a bit of each function each time.

因此,据此,该函数不一定会导致更快的执行,由于事件循环之间的切换,异步可能会变慢吗?我想,最终,一切都将分散在一个线程中,这与同步版本一样吗?

So according to this, the function doesn't necessarily result in faster execution, async is probably slower due to switching between event loop? I imagine that, at the end of the day, everything will be spread on a single thread which will be the same thing as synchronous version?

我可能缺少一些非常重要的概念,所以请告诉我.谢谢.

I am probably missing some very big concept so please let me know. Thanks.

编辑 如果异步操作像查询数据库之类的话,这是有道理的.基本上,nodejs只会说嘿,数据库为我处理,而我还要做其他事情".但是,我不了解的情况是nodejs自身中的自定义回调函数.

EDIT It makes sense if the asynchronous operations are like query DB etc. Basically nodejs will just say "Hey DB handle this for me while I'll do something else". However, the case I am not understanding is the self-defined callback function within nodejs itself.

EDIT2

function makeBurger() {
    var count = 0;
    count++; // 1 time
    ...
    count++; // 999999 times
    return count;
}

function makeBurgerAsync(callback) {
    var count = 0;
    count++; // 1 time
    ...
    count++; // 999999 times
    callback(count);
}

推荐答案

在node.js中,所有异步操作都在node.js Javascript单线程之外完成其任务.他们要么使用本机代码线程(例如node.js中的磁盘I/O),要么根本不使用线程(例如事件驱动的网络或计时器).

In node.js, all asynchronous operations accomplish their tasks outside of the node.js Javascript single thread. They either use a native code thread (such as disk I/O in node.js) or they don't use a thread at all (such as event driven networking or timers).

您不能执行完全用node.js Javascript编写的同步操作,而魔术般地使其异步.异步操作是异步的,因为它调用以本机代码实现并以实际上是异步的方式编写的某些函数.因此,要使某些内容异步,必须专门编写它以使用本身与异步本机代码实现异步的低级操作.

You can't take a synchronous operation written entirely in node.js Javascript and magically make it asynchronous. An asynchronous operation is asynchronous because it calls some function that is implemented in native code and written in a way to actually be asynchronous. So, to make something asynchronous, it has to be specifically written to use lower level operations that are themselves asynchronous with an asynchronous native code implementation.

这些带外操作,然后通过事件队列与主要的node.js Javascript线程进行通信.当这些异步操作之一完成时,它将事件添加到Javascript事件队列中,然后当单个node.js线程完成当前正在执行的操作时,它将从事件队列中获取下一个事件并调用与该事件相关联的回调

These out-of-band operations, then communicate with the main node.js Javascript thread via the event queue. When one of these asynchronous operations completes, it adds an event to the Javascript event queue and then when the single node.js thread finishes what it is currently doing, it grabs the next event from the event queue and calls the callback associated with that event.

因此,您可以有多个并行运行的异步操作.与并行运行相同的3个操作相比,并行运行3个操作通常将具有更短的端到端运行时间.

Thus, you can have multiple asynchronous operations running in parallel. And running 3 operations in parallel will usually have a shorter end-to-end running time than running those same 3 operations in sequence.

让我们研究现实世界中的异步情况,而不是您的伪代码:

Let's examine a real-world async situation rather than your pseudo-code:

function doSomething() {
   fs.readFile(fname, function(err, data) {
       console.log("file read");
   });
   setTimeout(function() {
       console.log("timer fired");
   }, 100);

   http.get(someUrl, function(err, response, body) {
       console.log("http get finished");
   });

   console.log("READY");
}

doSomething();

console.log("AFTER");

这是逐步进行的事情:

  1. fs.readFile()已启动.由于node.js使用线程池实现文件I/O,因此该操作将传递给node.js中的线程,它将在单独的线程中运行.
  2. 无需等待fs.readFile()完成,就调用setTimeout().这在libuv(node.js构建于其上的跨平台库)中使用了一个计时器子系统.这也是非阻塞的,因此注册了计时器,然后继续执行.
  3. http.get()被调用.这将发送所需的http请求,然后立即返回以进一步执行.
  4. console.log("READY")将运行.
  5. 这三个异步操作将以不确定的顺序完成(无论哪个先完成,其操作都将首先执行).为了便于讨论,假设setTimeout()首先完成.完成后,node.js中的某些内部组件将在事件队列中插入一个带有计时器事件和已注册回调的事件.当node.js主JS线程执行完任何其他JS后,它将从事件队列中获取下一个事件并调用与之关联的回调.
  6. 出于此描述的目的,假设在执行计时器回调时,fs.readFile()操作完成.使用自己的线程,它将在node.js事件队列中插入一个事件.
  7. 现在setTimeout()回调完成.此时,JS解释器将检查事件队列中是否还有其他事件. fs.readfile()事件在队列中,因此它捕获该事件并调用与此事件相关联的回调.该回调将执行并结束.
  8. 一段时间后,http.get()操作完成.在node.js内部,一个事件被添加到事件队列中.由于事件队列中没有其他内容,并且JS解释器当前未在执行,因此可以立即为该事件提供服务,并且可以调用http.get()的回调.
  1. fs.readFile() is initiated. Since node.js implements file I/O using a thread pool, this operation is passed off to a thread in node.js and it will run there in a separate thread.
  2. Without waiting for fs.readFile() to finish, setTimeout() is called. This uses a timer sub-system in libuv (the cross platform library that node.js is built on). This is also non-blocking so the timer is registered and then execution continues.
  3. http.get() is called. This will send the desired http request and then immediately return to further execution.
  4. console.log("READY") will run.
  5. The three asynchronous operations will complete in an indeterminate order (whichever one completes it's operation first will be done first). For purposes of this discussion, let's say the setTimeout() finishes first. When it finishes, some internals in node.js will insert an event in the event queue with the timer event and the registered callback. When the node.js main JS thread is done executing any other JS, it will grab the next event from the event queue and call the callback associated with it.
  6. For purposes of this description, let's say that while that timer callback is executing, the fs.readFile() operation finishes. Using it's own thread, it will insert an event in the node.js event queue.
  7. Now the setTimeout() callback finishes. At that point, the JS interpreter checks to see if there are any other events in the event queue. The fs.readfile() event is in the queue so it grabs that and calls the callback associated with that. That callback executes and finishes.
  8. Some time later, the http.get() operation finishes. Internal to node.js, an event is added to the event queue. Since there is nothing else in the event queue and the JS interpreter is not currently executing, that event can immediately be serviced and the callback for the http.get() can get called.

按照上述事件顺序,您会在控制台中看到以下内容:

Per the above sequence of events, you would see this in the console:

READY
AFTER
timer fired
file read
http get finished

请记住,这里最后三行的顺序是不确定的(这只是基于不可预测的执行速度),因此此处的精确顺序仅是示例.如果您需要以特定的顺序执行这些命令,或者需要知道所有这三个命令何时完成,则必须添加其他代码以进行跟踪.

Keep in mind that the order of the last three lines here is indeterminate (it's just based on unpredictable execution speed) so that precise order here is just an example. If you needed those to be executed in a specific order or needed to know when all three were done, then you would have to add additional code in order to track that.

由于您似乎正在尝试通过使当前不异步的异步操作使代码运行更快,所以让我重复一遍.您不能执行完全用Java编写的同步操作并使其异步".您必须从头开始重写它,以使用根本上不同的异步较低级别的操作,或者必须将其传递给其他进程来执行,然后在完成时得到通知(使用辅助进程或外部进程或本机代码)插件之类的东西.

Since it appears you are trying to make code run faster by making something asynchronous that isn't currently asynchronous, let me repeat. You can't take a synchronous operation written entirely in Javascript and "make it asynchronous". You'd have to rewrite it from scratch to use fundamentally different asynchronous lower level operations or you'd have to pass it off to some other process to execute and then get notified when it was done (using worker processes or external processes or native code plugins or something like that).

这篇关于单线程同步和异步混淆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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