单线程同步与异步混淆

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(使用前将#替换为@)

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

  • 未加载测试环境的节点 dotenv 文件

    我有两个 dotenv 文件 一个用于开发 另一个用于测试 const dotenv require dotenv if process env process env NODE ENV dotenv config path env pro
  • 将 html2pdf 生成的 pdf 发送回服务器

    我必须使用以下命令发送客户端生成的 PDFhtml2pdf到服务器 我已成功将生成的 PDF 转换为 base64 并希望使用axios 这是我的客户端代码 function myFunction var element document
  • 如何在 Jenkins 服务器上运行 Jest 测试

    我正在尝试运行我的Jest https facebook github io jest 在 Jenkins 部署期间进行测试 如果我 ssh 进入服务器 我可以 sudo 进入 Jenkins 用户并从工作区成功运行测试 但是 当我尝试从
  • 我应该如何在http post请求的请求负载中传递json数据

    我想知道如何在有效负载中传递 json 请求 例如 name test value test var post data var post options host this host path path method POST heade
  • Mongodb更新很多

    我正在使用express js 和 npm 模块 mongodb 进行开发 并以 mongodb 作为数据库 我有两个集合 即 用户 和 活动 一个用户可能有数千个活动 首先 我将用户的 id 姓名和图片 url 存储到 关系的活动文件 请
  • Child_process 处理带有回车符 (\r) 的 STDOUT 流

    我正在编写一个简单的应用程序 它允许工作中的内部系统请求从远程服务器到使用 REST 调用发起的另一个远程服务器的复制过程 使用 rsync 我已经对express框架足够熟悉 并且刚刚开始尝试child process库 并偶然发现了一个
  • nodejs mocha suite 未定义错误

    我正在尝试使用摩卡运行一些测试 但似乎无法克服这个错误 E tdd nodejs cart gt mocha cart test js node js 201 throw e process nextTick error or err Re
  • 使用异步工作流程并行化的最佳实践

    假设我想抓取一个网页并提取一些数据 我很可能会写这样的东西 let getAllHyperlinks url string async let req WebRequest Create url let rsp req GetRespons
  • python 中的异步编程

    python 中有异步编程的通用概念吗 我可以为一个函数分配一个回调 执行它并立即返回主程序流 无论该函数的执行需要多长时间吗 您所描述的 主程序流程在另一个函数执行时立即恢复 不是通常所说的 异步 又名 事件驱动 编程 而是 多任务 又名
  • 当请求新页面时,如何将 AngularJS 路由与 Express (Node.js) 结合使用?

    我正在使用 Express 它从静态目录加载 AngularJS 一般情况下我会要求http localhost 其中 Express 为我服务index html以及所有正确的 Angular 文件等 在我的 Angular 应用程序中
  • S3.getSignedUrl 接受多种内容类型

    我正在使用react s3 uploader节点包 它接受一个signingUrl用于获取用于将对象存储到 S3 中的signedUrl 目前 我已经配置了一个 lambda 函数 带有 API 网关端点 来生成此signedUrl 经过一
  • JavaScript 中的 Promise 有什么意义?

    一个承诺是一个 可能现在可用 或将来可用 或永远不可用的值 来源 MDN 假设我有一个想要处理图片的应用程序 图片已加载 例如在算法在后台使用它之后 或某种其他类型的延迟 现在我想检查一下图片是否可以在future 通过使用承诺 而不是回调
  • 为 Node.js 客户端应用程序保留 Firebase 用户

    我正在使用 Firebase 构建 Node js 命令行界面 CLI 用于与后端进行身份验证 我想避免让用户每次运行命令时都输入密码 相反 我想实现一个 登录 流程 将凭证保留到文件系统 该凭证可用于后续的无密码身份验证 直到用户 注销
  • NodeJS:调用 global.gc() 不会将内存减少到最低限度?

    为了调查内存泄漏 我设置了一条触发的路线global gc 在每个POST gc app post gc function req res global gc 但是 我注意到 如果我发送垃圾邮件此请求 每次都会越来越多地减少内存使用量 不应
  • 如何在 next-auth 中将数据添加到客户端 API?

    我目前正在使用凭据提供程序使用 next auth 进行授权 我有会话正在运行并且用户可以登录等 但是 在会话中我需要使用客户端 API 用户 名字 姓氏传递一些数据 用户名和电子邮件 默认情况下 客户端 API 传递名称 电子邮件和图像
  • 从自己的 gitlab 服务器安装节点模块

    我想从我们的 gitlab 服务器安装节点模块 这是存储库的链接 http ABCD GITLAB myGroup myNodeModule git http ABCD GITLAB myGroup myNodeModule git 根据n
  • 使用填充方法在 sails mongo 中进行深层关联?

    我是 sails js 的新手 我正在使用 sails js 与 Mongodb 我在我的 sails 应用程序中使用 populate 进行深层关联时遇到问题 我有这样的关系 Category has many to many relat
  • gcloud.app.deploy 错误响应:[9] 应用程序启动错误:[email protected] start /app 节点 app.js

    我对收到的错误消息感到好奇 环境 谷歌应用引擎 Nodejs 弹性环境 没有安装 Express 服务器 设置 app yaml 包含标准信息 server js 已创建但为空 此时此刻 app js 已创建 但目前为空 错误 错误 gcl
  • 未捕获 Func<> 的异常(异步)

    我有以下代码 为了进行此重现而进行了简化 显然 catch 异常块将包含更多逻辑 我有以下代码 void Main var result ExecuteAction async gt Will contain real async code
  • 使用 postgres 和 node js 在单个语句中执行多个查询

    我需要在像这样的单个语句中执行插入和删除查询 INSERT INTO COMPANY ID NAME VALUES 1 Paul DELETE FROM COMPANY WHERE ID 12 这是我用于执行查询的 node js 代码 p

随机推荐

  • 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