【问题标题】:How nodejs allows for better http request performance without multithreading?nodejs 如何在不使用多线程的情况下实现更好的 http 请求性能?
【发布时间】:2018-07-05 19:23:54
【问题描述】:

我已经阅读了很多内容并观看了很多关于 Nodejs 事件循环和 libuv 的 Youtube 讲座,但我仍然无法理解一些事情:根据这张幻灯片来自 Youtube libuv 背后的一位人的讲座:

http 请求是异步处理的,也就是说,它们一个接一个地进入事件循环,并且据我所知几乎按照 FIFO 顺序处理,因为线程不用于并行处理请求。但是,Nodejs 怎么能像equivalent Java 多线程服务器一样快速远程事件(更不用说实际上更快了)? libuv 下是否有使用线程运行这些请求的东西?

此外,如果每个请求都经过循环并且不使用线程来处理请求,那么Promise.all 是为了什么?

Javascript 也使用 libuv 还是只有 Nodejs 使用它?

【问题讨论】:

    标签: javascript node.js concurrency libuv


    【解决方案1】:

    Javascript 只有一个线程,想象一下以一个线程运行 Java servlet container。唯一的区别是JS 代码希望您在没有主动处理(主动使用 CPU 周期)任何内容时释放线程,而 Java 将希望您保持线程阻塞,直到您准备好返回响应,即使你在等待IO(即数据库查询)

    所以当我们说Nodejs 能够处理大量请求时,我们指的是大量IO bound 请求,大多数现实生活中的HTTP 请求都是如此。在服务CPU bound 请求方面,它无法执行任何多线程服务器,这是nodejs 的错误用例。在IO bound 请求的情况下,一旦请求到达IO,节点就会继续将请求推送到队列中。这些请求具有附加到它们的回调方法(用于 IO 响应,即 DB 查询输出),用于在事件循环期间检查的某些事件。因此,在运行事件循环期间,如果尚未触发任何事件,节点可以在队列中有一百万个请求并且不使用任何 CPU。而 servlet 容器在处理 100 万个请求之前就会死掉,因为它无法跟上一百万个线程所需的资源。

    现在甚至Servlet API 也具有async 功能request.startAsync(),它在等待IO 或任何其他事件发生时释放容器线程,从而释放线程以服务更多请求。

    【讨论】:

    • 你的回答没有解决我的问题:如果请求在事件循环中被一一处理,那么使用Promise.all有什么好处?另外,假设我们有4个请求。在节点中,这意味着它们将被一一执行。如果每个请求需要 500 毫秒才能得到响应,这将需要 2 秒(在完美条件下,例如节点进程不会在中间被阻塞)。在 Java 理论服务器中,将打开 4 个线程。假设创建一个线程所需的时间是 500 毫秒。那么Java中4个线程的执行需要1秒。我错过了什么?
    • Promise.all 的优点是能够在一组操作全部完成后做某事。 Promise 只是用来摆脱我们在使用 Javascript 时得到的回调链,它们使代码更有条理,更容易理解,它们与并行化无关。您提到的并发性不取决于正在运行的线程数,而是取决于您正在运行的 CPU 的数量。如果 Servlet 容器在 4CPU 机器上运行,它不会执行超过 4 个并发进程,即使有 1000 个线程。
    • 我认为 OP 假设 I/O 操作仅文件读写操作。所有的 HTTP 调用、setTimeout 调用、DB 调用都是异步的,这些调用将在 OS 线程上排队并执行。
    猜你喜欢
    • 2023-02-26
    • 2016-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-06
    相关资源
    最近更新 更多