当响应是异步的时,Node.js 中如何处理多个并发请求?

我可以想象 100 个请求到达单个 Node.js 服务器的情况。它们中的每一个都需要一些 DB 交互,这些交互是通过一些本机异步代码实现的 - 使用任务队列或至少微任务队列(例如 DB 驱动程序接口被承诺)。

当请求处理程序停止同步时,Node.js 如何返回响应?这 100 个来自描述的请求来自 api/web 客户端的连接会发生什么?

斯莱贝特曼

此功能在操作系统级别可用,称为(有趣的是)异步 I/O 或非阻塞 I/O(Windows 也调用/称为重叠 I/O)。

在最低级别,在 C(C#/Swift)中,操作系统提供了一个 API 来跟踪请求和响应。有多种 API 可用,具体取决于您使用的操作系统,Node.js 使用libuv在编译时自动选择最佳可用 API,但为了理解异步 API 的工作原理,让我们看看适用于所有平台的 API :select()系统调用。

select()函数看起来像这样:

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, time *timeout);

fd_set数据结构是你感兴趣的文件描述符的一组/列表的I / O活动。请记住,在 POSIX 套接字中也是文件描述符。您使用该 API 的方式如下:

// Pseudocode:

// Say you just sent a request to a mysql database and also sent a http
// request to google maps. You are waiting for data to come from both.
// Instead of calling `read()` which would block the thread you add
// the sockets to the read set:

add mysql_socket to readfds
add maps_socket to readfds

// Now you have nothing else to do so you are free to wait for network
// I/O. Great, call select:

select(2, &readfds, NULL, NULL, NULL);

// Select is a blocking call. Yes, non-blocking I/O involves calling a
// blocking function. Yes it sounds ironic but the main difference is
// that we are not blocking waiting for each individual I/O activity,
// we are waiting for ALL of them

// At some point select returns. This is where we check which request
// matches the response:

check readfds if mysql_socket is set {
    then call mysql_handler_callback()
}

check readfds if maps_socket is set {
    then call maps_handler_callback()
}

go to beginning of loop

所以基本上你的问题的答案是我们检查数据结构是什么套接字/文件刚刚触发了 I/O 活动并执行适当的代码。

毫无疑问,您可以轻松地发现如何概括这种代码模式:您可以将所有挂起的异步请求和回调保存在列表或数组中,并在select(). 这实际上是 Node.js(以及一般的 javascript)所做的。正是这个回调/文件描述符列表有时被称为事件队列——它本身并不是一个队列,只是你等待执行的事情的集合。

select()函数也有一个能用来实现最终超时参数setTimeout(),并setInterval()在浏览器中处理GUI事件,使我们可以在等待I / O运行代码。因为记住,select是阻塞的——我们只能在 select 返回时运行其他代码。通过仔细管理计时器,我们可以计算适当的值作为超时传递给select

fd_set数据结构是不实际的链接列表。在较旧的实现中,它是一个位域。更现代的实现可以改进位域,只要它符合 API。但是,这部分解释了为什么有这么多的竞争就像异步API pollepollkqueue等他们的建立是为了克服的局限性select不同的 API 以不同的方式跟踪文件描述符,一些使用链表,一些哈希表,一些迎合可扩展性(能够侦听数万个套接字)和一些迎合速度,并且大多数尝试比其他人做得更好. 无论他们使用什么,最终用于存储请求的只是一个跟踪文件描述符的数据结构

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章