单线程同步与异步混淆

2023-11-29

Assume makeBurger()需要 10 秒

在同步程序中,

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

这总共需要 25 秒才能执行。

所以对于 NodeJs 来说,我们制作了一个异步版本makeBurgerAsync()这也需要 10 秒。

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

   });
   makeBurgerAsync(function(count) {

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

由于它是单线程。我很难想象幕后到底发生了什么。

  1. 因此,可以肯定的是,当函数运行时,两个异步函数都会进入事件循环并且console.log("READY")会立即被处决。
  2. 但同时console.log("READY")正在执行,两个异步函数都没有真正完成任何工作,对吗?由于单线程占用 console.log 5 秒。
  3. console.log 完成后。 CPU 将有时间在两个异步之间切换,以便每次都可以运行每个函数的一部分。

因此,根据此,该函数不一定会导致更快的执行速度,异步可能会由于事件循环之间的切换而变慢?我想,最终,所有内容都将分布在单个线程上,这与同步版本是一样的吗?

我可能错过了一些非常大的概念,所以请告诉我。谢谢。

EDIT如果异步操作像查询数据库等,这是有意义的。基本上,nodejs 只会说“嘿,数据库为我处理这个,而我会做其他事情”。但是,我不明白的情况是nodejs本身内部自定义的回调函数。

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),要么根本不使用线程(例如事件驱动的网络或计时器)。

您无法将完全用 Node.js Javascript 编写的同步操作神奇地使其异步。异步操作是异步的,因为它调用一些在本机代码中实现并以实际异步方式编写的函数。因此,要使某些内容异步,必须专门编写它以使用本身与异步本机代码实现异步的较低级别操作。

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

因此,您可以并行运行多个异步操作。并行运行 3 个操作通常比顺序运行这 3 个操作的端到端运行时间更短。

让我们检查一下现实世界的异步情况而不是伪代码:

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. Now the setTimeout()回调完成。此时,JS 解释器会检查事件队列中是否还有其他事件。这fs.readfile()事件在队列中,因此它会获取该事件并调用与之关联的回调。该回调执行并完成。
  8. 一段时间后,http.get()操作完成。在 Node.js 内部,事件被添加到事件队列中。由于事件队列中没有其他内容,并且 JS 解释器当前未执行,因此可以立即处理该事件并回调http.get()可以被呼叫。

根据上述事件序列,您将在控制台中看到以下内容:

READY
AFTER
timer fired
file read
http get finished

请记住,这里最后三行的顺序是不确定的(它只是基于不可预测的执行速度),因此这里的精确顺序只是一个示例。如果您需要以特定顺序执行这些操作,或者需要知道这三个操作何时完成,那么您必须添加额外的代码来跟踪它们。


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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

单线程同步与异步混淆 的相关文章

  • 为什么流行的 JavaScript 运行时不能处理看似同步的异步脚本?

    As 牛仔在这里的评论中说道 https gist github com domenic 3889970 我们都希望 以类似于以下的风格编写 非阻塞 JavaScript 异步代码 try var foo getSomething asyn
  • npm installexpress-generator 不安装express

    我正在遵循 MEAN 堆栈教程 该教程要求我安装 Express 我运行这个 npm install g express generator 这是我的结果 username username Inspiron 3521 npm instal
  • 我如何制作 spring websocket + node.js 客户端

    我怎样才能在node js中创建一个websocket stomp客户端 WebSocketStompClient 就像我在java中用这行代码做的那样 WebSocketStompClient stompClient new WebSoc
  • Cordova 文件传输到节点服务器

    我正在使用 ng Cordova fileTransfer 插件尝试将用户相机胶卷中的照片上传到 Node Express 服务器 我正在获取照片的本地 URI 并尝试将其传递给插件 如下所示 cordovaFileTransfer upl
  • 如何使用中间件拦截botbuilder sdk v4中的消息?

    我有一个在 botbuilder V3 上运行的机器人 其中我使用了一个中间件解释here https learn microsoft com en us azure bot service nodejs bot builder nodej
  • 如何并行执行PowerShell函数多次?

    我不确定是否需要将其称为多线程 基于作业或异步的需求 但基本上我有一个 Powershell 脚本函数 它需要多个参数 并且我需要使用不同的参数多次调用它并让它们运行在平行下 目前 我这样调用该函数 Execute param1 param
  • 如何使用 Node.js 和 Axios 将文件上传到 AWS 中的预签名 URL?

    我有下一个场景 通过 AWS SDK 生成用于文件上传的签名 URL 尝试使用axios 或request npm包上传本地文件 但每次我都会出错 Status 403状态文本 禁止
  • 如何在qt中进行异步文件io?

    我想知道如何在qt中实现异步文件io 这在普通的 qt 中是否可以实现 或者有人需要使用另一个库 例如 libuv 来实现这样的事情 我正在查看 QDataStream 但即使它是一个 流 它也不是非阻塞的 我想一种解决方案是制作一个在内部
  • 如何在Sequelize中配置一对多关系?

    我目前正在使用 Express 和 Sequelize MySQL 想知道解决这个问题的最佳方法是什么 如果这是一个基本问题 我很抱歉 因为我对 Sequelize 甚至 SQL 数据库都很陌生 我有一个模型User像这样 export d
  • Jade - 从不同目录加载模板

    我正在尝试处理 Peepcode 的 Node js Full Stack 视频 他们似乎使用的是旧版本的express jade 没有提到使用块 扩展来渲染布局 应用程序中使用的设置是有一个为所有子应用程序加载的 views layout
  • 为什么需要 EndExecuteNonQuery()?

    文档here http msdn microsoft com en us library ca56w9se aspx指出 开发人员必须致电 EndExecuteNonQuery 方法完成 操作 我无法找到一个充分的理由来解释为什么会这样 或
  • process.stdout.on( 'data', ... ) 和 process.stderr.on( 'data', ... ) 的顺序

    我正在编写一个电子应用程序 该应用程序处理从电子内部执行的终端命令 我在执行时遇到了麻烦npm ls命令 从 cli 运行它时 依赖关系树会打印到 stdout 最后可能会出现一些来自 stderr 的警告 请参阅下面的屏幕截图 正确输出
  • 如何在Electron App中调用C# dll方法?

    我有一个电子应用程序 可以从读卡器读取信用卡详细信息 他们提供了一个 c dll 来与应用程序交互 我不知道如何从电子应用程序读取 dll 方法 首先使用以下命令检查 dll 中公开的函数依赖步行者 http www dependencyw
  • MongoDB:如何在更新之前对查询进行排序

    我正在编写一个 Meteor Node js 应用程序 它在后端使用 MongoDB 在我的代码中的某个时刻 我需要更新specific集合中的文档 我需要使用 Mongo 的 update 方法 但我在传递正确的 复杂的 查询以缩小到该特
  • 错误 [ERR_UNSUPPORTED_DIR_IMPORT]:尝试在本地启动 Nodejs 应用程序时导入目录

    我在尝试将我的应用程序部署到 Heroku 时陷入了一个循环 我的进口声明 例如import cors from cors 由于 无法在 Common JS 中加载 ES6 模块 错误 似乎阻止了应用程序在生产环境中启动 在本地运行得很好
  • 在 IBAction 中调用其他函数之前,如何使函数完成?

    我无法理解完成处理程序 我有一个 textFieldEditingDidChange IBAction 首先调用verify 文本字段输入上的函数然后是 if 语句在 apply 返回的布尔值上 问题是 if 语句在 verify 完成之前
  • 将同步 zip 操作转换为异步

    我们有一个现有的库 其中一些方法需要转换为异步方法 但是我不确定如何使用以下方法执行此操作 错误处理已被删除 该方法的目的是压缩文件并将其保存到磁盘 请注意 zip 类不公开任何异步方法 public static bool ZipAndS
  • 如何从node js发送json数据到html页面

    我已经使用 Node js Express 从 facebook 获取了一系列 json 数据 现在我想将数据发送到 html 页面 但我不知道如何发送数据并在 html 中对数据进行编码 如果您在 node js 中使用 Express
  • 将缓冲区数据转换为图像

    我如何将此缓冲区数据转换为图像 以便当循环结果并将其呈现在 img src 中时 它将呈现为用户可以看到的图像 我正在使用 ejs 来渲染它 span img class user with avatar src gt span 当我 co
  • 如何获取下载 URL 列表并从 Firebase 存储下载包含所有文件的 .ZIP 文件夹

    我的 Firebase 存储桶中的文件夹和子文件夹中有许多文件 我的实时 Firebase 数据库中有所有这些文件的下载 URL 列表 我正在尝试进行批量下载 最好创建一个 ZIP 文件夹供最终用户立即下载 其他几个帖子 例如如何从 Fir

随机推荐

  • MySQL 中加密数据的搜索过滤器

    查询说明 假设我有一个数据库表 它以加密形式存储所有用户的数据 我有一个功能 管理员可以搜索用户数据 现在的问题是 管理员将在文本框中输入普通文本 我必须根据管理员的输入过滤用户列表 在每次文本更改时 因此 与此同时 我拥有大量加密形式的数
  • 如何让tableFooterView始终位于UITableView的底部

    我有一个UITableView具有可变数量的部分 每个部分都有不同数量的单元格 并且每个部分都有页眉和页脚 我的UITableView还有一个tableFooterView我想始终将其保留在屏幕底部 除非表格太大而无法在屏幕上显示 然后ta
  • iphone 粘性菜单 jquery onscroll ios 9

    在更新到之前 这段代码在我的 iPhone 上运行良好iOS 9 0 1 13A404 但现在相同的代码似乎只有在手指松开后才能工作 或者在 jQuery 之后onscroll结束 当我快速滑动以使页面滚动时 document on scr
  • odbc_prepare 给出致命错误:允许的内存大小已耗尽

    我有一个 Debian 服务器 64 位 我想通过 PHP 将其连接到 AS400 的数据库 我已经安装了 IBM i Access for Linux 和 unixodbc 我已经遵循了这个教程 https www albertopica
  • 如何在插入语句的目标数据库名称中使用变量?

    我想声明一个服务器名称并在插入语句中使用该名称 到目前为止我收到的只是一条错误消息 declare machine nvarchar 6 declare bar nvarchar 3 set machine Name00 set bar f
  • 如何使用export_savedmodel保存和恢复tf.estimator.Estimator模型?

    我最近开始使用 Tensorflow 并尝试习惯 tf estimator Estimator 对象 我想做一些非常自然的先验事情 在训练了我的分类器之后 即 tf estimator Estimator 的实例 带有train方法 我想将
  • Pygame绘制抗锯齿填充多边形

    The documentation says For aapolygon use aalines with the closed parameter but pygame draw aalines doesn t let me specif
  • 如果主题带有星号,Outlook 电子邮件存档宏将不起作用

    我正在使用以下代码将我的电子邮件存档到目前完美运行的指定文件夹 除非电子邮件主题包含 然后这会给出调试消息 运行时错误 2147286788 800300fc 我可以在下面的代码中添加任何内容 使其忽略或将 替换为其他内容 以允许它自动存档
  • 火车站所需站台最少数量

    问题如下 给定到达火车站的所有火车的到达和出发时间 任务是找到火车站所需的最少站台数量 以便没有火车等待 火车可以在午夜之前到达 也可以在午夜之后到达 我理解传统问题是如何在没有火车可以在午夜之前到达并在午夜之后离开的条件下工作的 因为我见
  • iPhone 的 UIImageView isAnimating 返回错误

    我发现 isAnimating 即使在完成最大循环数并停止动画之后也会返回 true 然而 一旦你移动 UIImageView 它会突然更新并变为 false 以下是我的代码的重要部分 我以标准方式设置动画 UIImageView newI
  • ksoap2 org.xmlpull.v1.xmlpullparserexception 预期的 start_tag 错误

    下面是我编写的代码 用于验证用户登录凭据 使用 net编写的Web服务 private static final String SOAP ACTION http tempuri org getCredentials private stat
  • 查看 NSUserDefaults 文件内容

    有什么办法可以看到 NSUserDefaults 的内容吗 我可以从终端使用 pico 打开 plist 文件 但它显示奇怪的字符 我实际上看不到内容文件内容 有什么办法可以在 Xcode 中打开该文件吗 基本上 我希望能够查看和编辑 NS
  • iOS 上的 AWSS3TransferUtilityErrorDomain 代码=2

    AWSS3TransferUtilityErrorDomain Code 2 在 iOS 上上传达到 100 时出现此错误 而 Android 则工作正常 我在用react native s3 但这似乎是 sdk 或我的存储桶策略的问题 但
  • NameError:名称“self”未在 EXEC/EVAL 中定义

    我正在编码一些东西 并且有一个部分出现错误 但我找不到发生错误的原因 代码 示例 类似于错误部分 class Test def init self a 0 self x a self l 2 x for x in range a lt se
  • 使用 pip 安装 VTK

    我在 Arch Linux 上使用 Python 3 7 我一直在尝试用 pip 安装 Mayavi 但在安装 vtk 时总是失败 所以我发现即使尝试通过 pip 自行安装 vtk 应该有效 那个vtk确实没有安装 我收到此错误 sudo
  • 如何检测照片的拍摄角度,并像桌面应用程序在查看时自动旋转网站显示?

    如果我用相机拍照 它会存储设备的方向 角度 因此当我使用良好的应用程序在 PC 上查看图像时 它会显示自动旋转到 0 但是当我上传到网站时 它显示的是原始角度 所以图像看起来不太好 我怎样才能用 PHP 检测到这一点并旋转图像 并从它的元信
  • 如何在 Android 中用谷歌地图 v2 上的我的图标替换蓝点?

    我正在尝试用 Google 地图 v2 上我自己的图标替换蓝点 在地图上显示当前位置 我在下面尝试过 但没有成功 Android Maps API v2 更改我的位置图标 地图 V2 myLocation 蓝点回调 在 Google Map
  • 如何检测用户是否已登录 Firebase?

    我在 javascript 文件中使用 firebase node api 进行 Google 登录 firebase initializeApp config let provider new firebase auth GoogleAu
  • 具有多个 sql_variant 参数的 SQLCLR 自定义聚合

    Hy 几个月前我发布了一个关于 CLR 用户定义聚合的问题post 这就像一个魅力 但现在我想使用 sql variant 类型的两个参数来实现完全相同的功能 就像我之前的文章一样 这两个函数是 sMax 和 sMin 并且将根据第二个值返
  • 单线程同步与异步混淆

    Assume makeBurger 需要 10 秒 在同步程序中 function serveBurger makeBurger makeBurger console log READY Assume takes 5 seconds to