javascript - Promise.all()vs等待

标签 javascript node.js promise async-await event-loop

我试图了解node.js单线程体系结构和eventloop,以使我们的应用程序更高效。因此,请考虑这种情况,其中我必须对一个HTTP api调用进行多个数据库调用。我可以使用Promise.all()或使用单独的await做到这一点。
示例:
使用异步/等待

await inserToTable1();
await insertToTable2();
await updateTable3();
使用Promise.all()我可以通过
await Promise.all[inserToTable1(), insertToTable2(), updateTable3()]
在这里,对于给定时间的一个API命中而言,Promise.all()将更快地返回响应,因为它会并行触发数据库调用。但是,如果我每秒有1000次API命中,会有什么区别吗?对于这种情况,Promise.all()对eventloop更好吗?
更新
假设以下内容,
通过1000次API命中,我的意思是应用程序的总体流量。考虑有20-25个API。其中的一些可能会执行数据库操作,一些可能会进行一些http调用,等等。而且,我们绝不会达到数据库池的最大连接数。
提前致谢!!

最佳答案

与通常的系统设计一样,答案是:取决于
有很多因素决定了两者的性能。通常,等待一个Promise.all()会并行等待所有请求。
事件循环
事件循环恰好使用0%的CPU时间来等待请求。请参阅我对这个相关问题的回答,以了解事件循环的工作原理:Performance of NodeJS with large amount of callbacks
因此,从事件循环的角度来看,顺序请求和与Promise.all()并行请求之间没有真正的区别。因此,如果这是您问题的核心,我想答案是,则两者之间的没有区别。
但是,处理回调确实会占用CPU时间。同样,完成执行所有回调的时间相同。因此,从CPU性能的角度来看,再次与并无区别。
但是,以并行方式发出请求确实会减少整体执行时间。首先,如果服务是多线程的,那么您实质上是通过发出并行请求来使用它的多线程性。这是使node.js快速运行的原因,即使它是单线程的也是如此。
即使您所请求的服务不是多线程的,并且实际上是按顺序处理请求的,或者您所请求的服务器是单核CPU(如今很少见,但您仍然可以租用单核虚拟机),那么并行请求由于您的操作系统可以在单个以太网帧中发送多个请求,因此减少了网络开销,从而分摊了多个请求中数据包报头的开销。但是,这样做确实有 yield ,递减率超过了大约六个并行请求。
千个请求
您假设发出了1000个请求。天气是否并行等待1000个 promise 实际上会导致并行请求取决于API在网络级别的工作方式。
连接池。
许多数据库库都实现了连接池。也就是说,该库将打开一些与数据库的连接,例如5,并重用这些连接。
在某些实现中,通过这样的库发出1000个请求将导致该库的低级网络代码一次批处理5个请求。这意味着您最多可以有5个并行请求(假设有5个连接池)。在这种情况下,发出1000个并行请求是绝对安全的。
但是,某些实现具有可扩展的连接池。在这样的实现中,发出1000个并行请求将导致您的软件打开1000个套接字来访问远程资源。在这种情况下,发出1000个并行请求的安全性将取决于远程服务器允许这样做的天气。
连接限制。
大多数数据库(例如Mysql和Postgresql)允许管理员配置连接限制(例如5),以使该数据库将拒绝的连接数超出每个IP地址的有限连接数。如果您使用的库无法自动管理与数据库的最大连接数,则数据库将接受前5个请求,并拒绝其余5个请求,直到另一个插槽可用为止(有可能在node.js完成打开第1000个套接字之前释放连接) )。在这种情况下,您无法成功发出1000个并行请求-您需要管理发出的并行请求数量。
一些API服务还限制了您可以并行建立的连接数。例如,“Google map ”将您每秒限制为500个请求。因此,等待1000个并行请求将导致50%的请求失败,并可能导致您的API key 或IP地址被禁止。
网络限制。
理论上,您的计算机或服务器可以打开的套接字数量有限制。但是,这个数字非常高,因此在这里不值得讨论。
但是,当前存在的所有OS都限制了打开套接字的最大数量。在Linux(例如Ubuntu和Android)和Unix(例如MacOSX和iOS)上,套接字被实现为文件描述符。每个进程分配的文件描述符数量最大。
对于Linux,此数字通常默认为1024个文件。请注意,默认情况下,进程会打开3个文件描述符:stdin,stdout和stderr。剩下1021个文件描述符由文件和套接字共享。因此,您在并行裙中的1000个请求非常接近此数字,并且如果两个客户端尝试同时发出1000个并行请求,则可能失败。
可以增加这个数字,但确实有一个硬性限制。您现在可以在Linux上配置的文件描述符的最大数量为590432。但是,这种极端配置只能在没有运行守护程序(或其他后台程序)的单个用户系统上正常运行。
该怎么办?
编写网络代码时的第一条规则是尽量不要破坏网络。您一次提出的请求数量要合理。您可以将请求分批处理到服务期望的极限。
使用异步/等待很容易。您可以执行以下操作:

let parallel_requests = 10;

while (one_thousand_requests.length > 0) {
    let batch = [];

    for (let i=0;i<parallel_requests;i++) {
        let req = one_thousand_requests.pop();
        if (req) {
            batch.push(req());
        }
    }

    await Promise.all(batch);
}
通常,您可以并行发出的请求越多,总体处理时间就会越短(越短)。我想这就是您想听到的。但是您需要在并行性与上述因素之间取得平衡。 5一般就可以。大概十个100将取决于服务器对请求的响应。 1000或更多,安装服务器的管理员可能必须调整他的操作系统。

关于javascript - Promise.all()vs等待,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62862691/

相关文章:

javascript - 更改 jQuery 加载代码

javascript - 如何使用正则表达式删除字符串集

javascript - Node JS 无法在字符串缓冲区上使用多个拆分和 trim 函数

javascript - 在前端 promise 中链接相互依赖的服务器调用是一种不好的做法吗?

javascript - 如何简化深层嵌套的 Promise

javascript - 在 Knockout.js 中绑定(bind)更新

node.js - Pusher JS 在某些网络中无法从 Node JS 运行

javascript - 如何在 Node JS 中读取 servlet 响应输出流?

angular - 什么时候使用 Promise 而不是 observable?

javascript - 使用 HTML 实体设置元素值