我已经阅读了很多相关的资料(包括Stack Overflow),但仍有几个问题。我的目标是:
1.从多个不同来源中提炼出总结,以便确认我的结论是否正确。 2.询问一些关于Node线程和性能的问题,这些问题我在研究中没有找到确切的答案。
Node具有单线程、异步事件处理架构。
单线程: - 有一个单一的事件线程来分派异步任务(通常是I/O操作,也可能是计算),并执行回调函数(即处理异步任务结果)。
- 事件线程在无限制的“事件循环”中运行,完成上述两个工作:a)通过分派异步任务来处理请求,b)发现先前的异步任务结果已经准备好,并执行回调函数来处理结果。
- 常用的比喻是餐馆服务员:事件线程就像是一个超级快的服务员,从餐厅接收订单(处理请求)并将订单送到厨房准备(分派异步任务),同时在食物准备好后注意到并将其送回餐桌(执行回调函数)。
- 服务员不做任何烹饪工作;他的工作是尽可能快地在餐厅和厨房之间穿梭。如果他在餐厅中拖延了一个订单,或者被迫回到厨房准备某个菜肴,系统将变得效率低下,吞吐量也会降低。
...
FIRST [ASYNC: read a file, figure out what to get from the database] THEN
[ASYNC: query the database] THEN
[format and return the result].
上面标记为“ASYNC”的工作是“厨房工作”,而“FIRST []”和“THEN []”表示服务员启动回调的参与。
这样的链在程序上有三种常见的表示方式:
1. 嵌套函数/回调 2. 使用.then()链接的promises 3. 调用异步结果的异步方法。
所有这些编程方法基本上是等效的,尽管异步/等待似乎是最干净的,并且使得关于异步编程的推理更容易。
以下是我对正在发生的事情的心理描绘...是否正确?非常感谢您的评论!
问题:
我的问题涉及使用操作系统支持的异步操作,实际上谁执行异步工作以及这种架构比“针对每个请求生成一个线程”(即多个厨师)架构更高效的方式:
1. Node库已经通过使用跨平台异步库libuv来设计为异步的,是吗?这里的想法是libuv向node(在所有平台上)提供一致的异步I/O接口,但在底层使用平台相关的异步I/O操作。在I/O请求“一直下去”到受操作系统支持的异步操作的情况下,谁“做工作”等待I/O返回并触发节点?是内核,使用内核线程吗?如果不是,那是谁?在任何情况下,这个实体可以处理多少请求?
2. 我读到libuv在内部也使用线程池(通常是pthread,每个核心一个?)。这是为了“包装”不“一直下去”的操作,以便线程可以用来等待同步操作,以便libuv可以提供异步API吗?
3. 关于性能,通常给出的说明是解释类似node架构可以提供的性能提升:想象一下(可能更慢和更胖)的针对每个请求生成一个线程的方法——存在延迟、CPU和内存开销,因为产生了一堆只是坐在那里等待I/O完成的线程(即使它们没有忙等待),然后拆除它们,而node主要通过使用长期活动的事件线程将异步I/O分派给OS/内核来消除这些问题,是吗?但归根结底,有些东西正在互斥锁上睡觉并在I/O准备好时被唤醒...这个想法是如果是内核,那么比用户空间线程更有效率?最后,如果请求由libuv的线程池处理,会怎样呢?这似乎类似于针对每个请求生成一个线程的方法,除了使用池的效率(避免启动和拆除),但在这种情况下,当有许多请求和池有积压时会发生什么?...延迟增加,现在你比针对每个请求生成一个线程的方法做得更差了,是吗?