发出连续的 HTTP 请求是节点中的阻塞操作吗?

2024-03-02

请注意,与我的问题无关的信息将被“引用”

像这样(随意跳过这些)。

Problem

我正在使用节点代表多个客户端发出有序的 HTTP 请求。这样,客户端最初需要加载几个不同的页面才能获得所需的结果,现在只需要通过我的服务器发出一个请求。我目前使用“async”模块进行流量控制,使用“request”模块发出 HTTP 请求。大约有 5 个回调,使用 console.time,从开始到结束大约需要 2 秒(下面包含草图代码)。

现在我对节点相当缺乏经验,但我知道 节点的单线程性质。虽然我已经多次阅读该节点 不是为 CPU 密集型任务而构建的,我不太明白那是什么 意思是到现在为止。如果我对正在发生的事情有正确的理解, 这意味着我目前拥有的(正在开发中的)绝不是 将扩展到甚至超过 10 个客户。

Question

由于我不是节点专家,我问这个问题(在标题中)是为了确认发出多个连续的 HTTP 请求确实是阻塞的。

Epilogue

如果是这样的话,我希望我会问一个不同的问题(在进行适当的研究之后)讨论各种可能的解决方案,我是否应该选择继续在节点中解决这个问题(它本身可能不适合我正在尝试的事情)去做)。

其他结束语

如果这个问题不够详细,太菜鸟,或者语言特别华丽(我尽量简洁),我真的很抱歉。

感谢所有可以帮助我解决问题的人!

我之前提到的代码:

var async = require('async');
var request = require('request');

...

async.waterfall([
    function(cb) {
        console.time('1');

        request(someUrl1, function(err, res, body) {
            // load and parse the given web page.

            // make a callback with data parsed from the web page
        });
    },
    function(someParameters, cb) {
        console.timeEnd('1');
        console.time('2');

        request({url: someUrl2, method: 'POST', form: {/* data */}}, function(err, res, body) {
            // more computation

            // make a callback with a session cookie given by the visited url
        });
    },
    function(jar, cb) {
        console.timeEnd('2');
        console.time('3');

        request({url: someUrl3, method: 'GET', jar: jar /* cookie from the previous callback */}, function(err, res, body) {
            // do more parsing + computation

            // make another callback with the results
        });
    },
    function(moreParameters, cb) {
        console.timeEnd('3');
        console.time('4');

        request({url: someUrl4, method: 'POST', jar: jar, form : {/*data*/}}, function(err, res, body) {
            // make final callback after some more computation.
            //This part takes about ~1s to complete
        });
    }
], function (err, result) {
    console.timeEnd('4'); //
    res.status(200).send();
});

通常,node.js 中的 I/O 是非阻塞的。您可以通过同时向服务器发出多个请求来测试这一点。例如,如果每个请求需要 1 秒来处理,则阻塞服务器将花费 2 秒来处理 2 个并发请求,但非阻塞服务器将只需要 1 秒多一点的时间来处理这两个请求。

但是,您可以通过使用故意阻止请求同步请求 https://github.com/ForbesLindesay/sync-request模块而不是request https://github.com/request/request。显然,不建议服务器这样做。

下面是一些代码来演示阻塞 I/O 和非阻塞 I/O 之间的区别:

var req = require('request');
var sync = require('sync-request');

// Load example.com N times (yes, it's a real website):
var N = 10;

console.log('BLOCKING test ==========');
var start = new Date().valueOf();
for (var i=0;i<N;i++) {
    var res = sync('GET','http://www.example.com')
    console.log('Downloaded ' + res.getBody().length + ' bytes');
}
var end = new Date().valueOf();
console.log('Total time: ' + (end-start) + 'ms');

console.log('NON-BLOCKING test ======');
var loaded = 0;
var start = new Date().valueOf();
for (var i=0;i<N;i++) {
    req('http://www.example.com',function( err, response, body ) {
        loaded++;
        console.log('Downloaded ' + body.length + ' bytes');
        if (loaded == N) {
            var end = new Date().valueOf();
            console.log('Total time: ' + (end-start) + 'ms');
        }
    })
}

运行上面的代码,您将看到非阻塞测试处理所有请求所需的时间与处理单个请求的时间大致相同(例如,如果设置 N = 10,则非阻塞代码执行 10 次比阻塞代码更快)。这清楚地表明请求是非阻塞的。


补充答案:

您还提到您担心您的进程会占用 CPU 资源。但在您的代码中,您没有对 CPU 效用进行基准测试。您混合了网络请求时间(I/O,我们知道它是非阻塞的)和 CPU 处理时间。要测量请求处于阻塞模式的时间,请将代码更改为:

async.waterfall([
    function(cb) {
        request(someUrl1, function(err, res, body) {
            console.time('1');
            // load and parse the given web page.
            console.timeEnd('1');
            // make a callback with data parsed from the web page
        });
    },
    function(someParameters, cb) {
        request({url: someUrl2, method: 'POST', form: {/* data */}}, function(err, res, body) {
            console.time('2');
            // more computation
            console.timeEnd('2');

            // make a callback with a session cookie given by the visited url
        });
    },
    function(jar, cb) {
        request({url: someUrl3, method: 'GET', jar: jar /* cookie from the previous callback */}, function(err, res, body) {
            console.time('3');
            // do more parsing + computation
            console.timeEnd('3');
            // make another callback with the results
        });
    },
    function(moreParameters, cb) {
        request({url: someUrl4, method: 'POST', jar: jar, form : {/*data*/}}, function(err, res, body) {
            console.time('4');
            // some more computation.
            console.timeEnd('4');

            // make final callback
        });
    }
], function (err, result) {
    res.status(200).send();
});

您的代码仅阻塞在“更多计算”部分。因此,您可以完全忽略等待其他部分执行所花费的任何时间。事实上,这正是节点可以同时服务多个请求的方式。在等待其他部分调用各自的回调时(您提到这可能需要长达 1 秒),节点可以执行其他 javascript 代码并处理其他请求。

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

发出连续的 HTTP 请求是节点中的阻塞操作吗? 的相关文章

随机推荐

  • Android/Java:将任何字符串转换为颜色(十六进制)

    有没有办法像加密 哈希函数一样从 Java Android 中的任何字符串生成颜色 例子 字符串 Home 生成类似 FF1234 的颜色 字符串 Sky 生成类似 00CC33 的颜色 没有随机化 因此 系统将始终为该字符串计算相同的颜色
  • Azure eventhub 多个分区键指向同一分区

    我们正在开发一个多租户应用程序 其中 eventhub 将在不同租户之间共享 我们将在租户之间分配分区 每个租户将在不同的分区上发送消息 我们希望在分区级别对租户进行身份验证 正如 Microsoft 网站上所述 我们根据租户 ID 定义分
  • java swing布局两个组件

    A B
  • getaddrinfo:如果指定了节点名,AI_PASSIVE 以什么方式被忽略?

    引用自规格获取地址信息 http pubs opengroup org onlinepubs 009695399 functions freeaddrinfo html If the AI PASSIVE如果指定了标志 则返回的地址信息应适
  • 检查元素是否包含数组中的任何类

    我有以下要素 div class one two three four five six seven eight div div class one two three four five six seven eight ten div d
  • 如何防止不良项目引用?

    我们使用带有 TFS 的 C 项目作为源代码控制和 CI 构建 我不断发现其他开发人员正在引用来自的程序集 Bin当他们应该使用我们的目录时 目录不正确 Libs文件夹 我们保存第 3 方程序集的地方 作为解决方案构建或 CI 构建 我们也
  • 如何在 vim 中打开旧文件列表中的文件?

    在 vim 中 我可以输入 oldfiles查看我之前编辑过的文件列表 很棒的功能 但现在我想将该列表中的一个或多个文件打开到缓冲区中 我怎样才能做到这一点 一旦您位于列表底部 您应该按 并使用这个 奇怪 的符号发出命令 command l
  • 使用查询范围热切加载相关模型

    说我有一个模型Box其中包含许多小部件 小部件可以是活动的或非活动的 布尔值 这Widget模型有一个可以过滤结果的查询范围 模型 box php class Box extends Eloquent public function wid
  • 在 R 中创建数字同心环递增的矩阵

    我需要在 R 中编写一个函数来创建一个由递增的同心数字环组成的矩阵 该函数的参数是层数 例如 如果 x 3 矩阵将如下所示 1 1 1 1 1 1 2 2 2 1 1 2 3 2 1 1 2 2 2 1 1 1 1 1 1 我不知道该怎么做
  • 在 WooCommerce 电子邮件模板中获取产品名称和描述

    我试图在 WooCommerce 电子邮件模板中发送电子邮件时获取产品描述和产品名称 我能够获取产品 ID order id trim str replace order gt get items 使用此代码 但是当我试图获取它的描述和产品
  • 在 Symfony 应用程序/控制台中启用 Doctrine DBAL 命令

    当使用 Bare Bone Doctrine 和开箱即用的命令行时 有两个命令可用 但在 Symfony 和 Doctrine 中使用时似乎不可用 app console dbal dbal import Import SQL file s
  • MVC3 razor 创建 HtmlButtonExtension 时出错

    我正在尝试使用在我的页面上创建一个自定义 html 按钮this https stackoverflow com questions 5955571 theres no html button public static class Htm
  • oci8、php7 和 Oracle 10.1 兼容性

    我必须从以下版本升级系统php5 6 to php7 2 该系统使用一个oracle 10 1数据库 现在我尝试收集所有信息 但仍然对之间的兼容性感到困惑php oci8 instant client和数据库 我读到 对于 php7 我至少
  • ASCII 码实际上是 7 位还是 8 位?

    我的老师告诉我 ASCII 是一种 8 位字符编码方案 但它仅定义为 0 127 代码 这意味着它可以容纳 7 位 那么难道不能说 ASCII 实际上是一个 7 位代码吗 当说 ASCII 是一个 8 位代码时 我们到底在说什么 ASCII
  • ESP32 上的 Web 服务器:如何自动更新和显示来自服务器的传感器值?

    我在 ESP32 上有一个网络服务器 在该服务器上有一个主页 我想每隔 x 秒自动更新主页上的传感器值 无需用户输入 我无法访问文件系统 该传感器直接连接到 ESP32 传感器值位于我的 C 程序中 存储在变量中并定期更新 变量是全局的 以
  • 使用 lambda 编写枚举函数

    我收到了这个练习 写一个函数enumerate它接受一个列表并返回一个列表 元组包含 index item 对于列表中的每个项目 我的问题是我无法将索引和值插入一个或多个for循环 这是我设法制作的代码 a a b c a b c inde
  • WELD-001409 类型 [EagerBeansRepository] ​​的依赖关系不明确

    我正在尝试将 JSF 应用程序迁移到 CDI 我实施了以下更改 添加一个空的 beans xml 文件到 WEB INF 将 ManagedBean 更改为 Named 将我拥有的所有范围更改为 CDI 范围 会话 视图 请求 将所有 EJ
  • 在 GCD 串行队列上调度和无效 NSTimers 是否安全?

    这样做的正确方法是什么 这NSTimer文档是这样说的 特别注意事项 您必须从以下线程发送此消息 安装了计时器 如果您从其他人发送此消息 线程中 与计时器关联的输入源可能不会被删除 从其运行循环中 这可能会阻止线程退出 适当地 Since
  • git bare 存储库中的“fetch --all”不会将本地分支同步到远程分支

    我正在尝试定期同步 git bare 存储库 我的本地分支是使用 track 选项创建的 这是我的配置 没有不必要的东西 core bare true remote origin url email protected cdn cgi l
  • 发出连续的 HTTP 请求是节点中的阻塞操作吗?

    请注意 与我的问题无关的信息将被 引用 像这样 随意跳过这些 Problem 我正在使用节点代表多个客户端发出有序的 HTTP 请求 这样 客户端最初需要加载几个不同的页面才能获得所需的结果 现在只需要通过我的服务器发出一个请求 我目前使用