我可以想象有100个请求到达单个Node.js服务器的情况。它们中的每一个都需要一些DB交互,这些交互是使用任务队列或至少使用微任务队列(例如DB驱动程序接口得到验证)实现的一些本机异步代码。
当请求处理程序停止同步时,Node.js如何返回响应?这100个来自描述的请求从api/web客户端连接到哪里会发生什么?
发布于 2020-05-05 06:40:18
此特性在OS级别上可用,并被称为异步I/O或非阻塞I/O (Windows也调用/调用它重叠的I/O) (非常有趣)。
在最低级别,在C (C#/Swift)中,操作系统提供一个API来跟踪请求和响应。根据操作系统的不同,有不同的API可用,Node.js使用利布夫在编译时自动选择最佳可用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,如poll
、epoll
、kqueue
等,它们的创建是为了克服select
的局限性。不同的API以不同的方式跟踪文件描述符,一些使用链接列表、一些哈希表、一些满足可伸缩性(能够侦听数万个套接字)和一些满足速度的需求,大多数API都试图做到这两个方面都优于其他API。不管他们使用什么,最终用于存储请求的只是一种数据结构,可以跟踪文件描述符。
https://stackoverflow.com/questions/61606484
复制相似问题