[今晚我想来点 Express 佐 MVC 分层架构] DAY 28 - node.js 与线程 (上)

node.js 之所以能够运行 JavaScript 程序码,是因为底层依赖 google 在 chrome 中使用的 V8 引擎,它是一个跑得非常快的 JavaScript 引擎,速度快到 让 JavaScript 的速度胜过诸多语言,不过仍然没有突破 JavaScript 的限制,就是 单线程问题

https://upload.wikimedia.org/wikipedia/commons/thumb/3/3f/V8_JavaScript_engine_logo_2.svg/200px-V8_JavaScript_engine_logo_2.svg.png
图片来源

线程是什麽?

线程就是所谓的执行绪,用很简单的比喻来说明线程的概念:

单线程

假设今天去某超市采购中秋烤肉的材料,这家超市释出很好的折扣,让大家愿意拿出三倍券来该超市进行采购,不过生意实在太好,超出业主预期,业主当初预期聘请一名结帐人员就能够负荷,结果现在大排长龙,结帐人员忙得不可开交,客人们也等到头发都白了...

从上面可以看出只有一人在处理结帐流程,当结帐的人变多了,自然会形成忙不过来的状况。在电脑的世界里也有相同的问题,假设电脑是单核心的 CPU,那每个资源请求就是只能 透过一个核心来处理

多线程

延续上面超市的例子,业主设置了多个收银台,并且聘请了多名结帐人员来 分散结帐人流,降低了所有结帐人员的工作量,更能够缩短客户排队的时间。可以发现业主透过增加设备与人员来解决结帐问题,在电脑的世界也是一样,透过资源的扩充来弥补硬体资源上的不足,让每个资源请求能够 透过多个核心来处理

node.js 线程问题

看完上述的举例之後应该会有部分人感到困惑:明明电脑是多核心处理器,为什麽说 JavaScript 只能单线程?这个道理很简单,同样用超市举例来说明,假设今天这家超市本来就已经有 8 个收银台,但业主就是只聘请一名结帐人员,那有再多收银台也没有意义,简单来说就是 JavaScript 本身只支援使用单一线程来运行,CPU 再多核也无法改善这个问题。

不过说 node.js 只支援单线程又有点不太对,主要是因为 node.js 不是只靠 V8 引擎在运作,底层依赖的东西非常多,这时候就要搬出 node.js 的运作图了:
https://ithelp.ithome.com.tw/upload/images/20200919/20119338oWGYhhPwi7.png

node Application 就是我们平常写的 node.js 应用程序,在这个层级的程序码会透过 V8 引擎 执行,并经由 node.js API 去跟使用 C 语言撰写的 libuv 进行互动,而 libuv 提供了 Event Loop 让单线程的操作可以实现 异步不阻塞,这也是 node.js 可以执行得 像多线程 的原因。事实上大多数情况 node.js 是单线程在运作,但只要是跟 I/O 有关的操作,libuv 就会使用多线程的方法处理,等於说 node.js 并不完全是单线程

Event Loop?异步不阻塞?

这是一个很有趣的机制,再沿用超市的例子来说明:在只有一名结帐人员的情况下,已经很忙了,这时遇到了一名客人问说他要结帐的 X 牌洗发精是否有一整箱的,他想要买整箱的量,此时的结帐人员透过对讲机请仓库人员协助处理,於是先请他到旁边等待,并帮下一位客人结帐,等到整箱的洗发精来了之後,结帐人员就继续帮他结帐,这样的处理方式可以避免浪费过多的时间在等待。而 Event Loop 就是在处理这件事,透过 Event Queue 储存需要等待的异步行为并持续关注,等到该行为已经结束异步行为时,就会再把它继续处理完,这样的机制可以让在後方的行为不受等待所影响,形成永不阻塞的通道,正是所谓异步不阻塞。

这跟 Express 有何关系?

跟 Express 并没有直接关系,但绝对有间接关系,因为 Express 就是 node.js 的 Web 框架,而线程这件事又会影响到整体系统的效能,所以我认为这是蛮值得提的内容,试想今天是一个大型系统并且只用单线程在运行,资源根本没有用到最佳化,使用者也无法体验到最佳的系统效能,当流量上来的时候,客服电话也会着上来,不只系统会负荷不了,客服人员也会接到手酸!

该怎麽解决线程问题?

虽然 node.js 背後有 Event Loop 解决异步阻塞的问题,但终究是用单线程处理大多数的使用场景,当流量很大的时候仍然是个挑战。为了解决这个问题,node.js 推出了 丛集(Cluster) 功能。

丛集 (Cluster) 是什麽?

丛集可以实现多线程的功能,将程序分为 父程序(master)子程序(worker),他们之间的程序码是共享的,但记忆体空间并非共享的,简单来说就是:跑一个 node.js 的应用只能单线程,那我跑多个不就可以多线程了吗!透过 Cluster 可以使他们共享同一个 port,这样用起来就跟多线程没两样了!
https://ithelp.ithome.com.tw/upload/images/20200919/20119338ngjLnRANcv.png

丛集是很棒的功能,但我并不打算自己实作它,因为已经有造好的轮子可以使用,我们只需要了解这基本概念即可!

小结

有的时候要开发一个东西,先去了解这些工具背後的基本运作模式事实上是有帮助的,在知道如何运作之後,要去实作较有深度的功能时,会比较知道为什麽需要这麽做,比如说:使用 Cluster 开启多线程,就是为了解决 node.js 在大多数场景下只能以单线程来运行。我在最後有提到已经有造好的轮子可以实现 Cluster 所做的事情,这部分我就在下一篇进行说明吧!


<<:  Day28 bash与history

>>:  Day 28 建立 RWD media query breakpoint

Day14 AR眼镜感测器嘻勒感测虾米 可以玩/用不就好了?

今天来说说(为什麽要)感测器,它是什麽?影响的东西。 感测器是用於侦测环境中所生事件或变化,并将此讯...

云端资安之GCP篇(Google Cloud Platform)

你终究要上云端的,那为什麽不一开始就上? 接下来三天是关於三大云端服务, 分别就是GCP(Googl...

[Day07] 团队系统设计 - 规画迷思

前一篇文章,我提到来自 PO 与 QA 的两个张力-舒缓系统,是主管/ Scrum Master 下...

【把玩Azure DevOps】Day10 CI/CD从这里:第2个Pipeline,建立共用的Build Pipeline

从前面的几篇文章应该已经知道建立新的Pipeline可以从哪里开始,所以废话不多说,第二个Pipel...

DAY01 - 初次参加铁人赛的中年大叔の简介

前言: 这是大叔的第一次...参加IT铁人赛,不免俗的在参赛的第一篇要交代一下个人背景与参赛动机。 ...