Node.js 由于其设计而饱受批评。 与 Java, C 或 Python 等编程语言相比,Node.js 不能直接访问线程显得有些奇怪。咱们怎么能并发地执行任务呢?git
好吧,实际上早在 Node.js 11 以前咱们就能够使用 cluster 模块来并发/并行地执行代码,正如 前一篇文章 所述。github
可是若是咱们处在一台只有一个核的服务器上呢,咱们要怎么作?数据库
在 Node.js 11 里咱们有了 worker_thread 模块,它容许咱们在单核上建立(spawn)多个线程。实际上在 Node.js 10 里面咱们也能经过添加 --experimental-worker
标志来使用这个模块,可是在 Node.js 11 里咱们终于不用再加它了!编程
让咱们假设须要建立一个包含 100 万个用户 的文件,每一个用户由 first name、middle name 和 last name 组成。数组
我发现了下面这个了不得的 Github 项目,它能提供一个包含 first、middle 和 last names 的数组。咱们将在项目中使用这些 JSON 文件:promise
让咱们经过下面的文件结构建立一个新项目:多线程
那么让咱们从 main.js
文件开始:并发
如你所见,咱们使用了 fs-extra
包。它和 fs
很像,可是全部的函数都返回一个 promise。它解决了这种操做带来的一个大问题:内存使用。实际上,若是咱们尝试使用 Node.js 打开太多文件,它将产生一个异常而后杀掉主进程,由于它没法同时处理全部打开的这些文件(而且内存不足)。在咱们的 for
循环中,await
会在操做结束前使循环停止:经过这种方式,咱们在每一个迭代中就老是只会打开一个文件。
让咱们看一下 utils/index.js
文件:
在这里咱们仅仅只是从任意数组里面随机取出一个值。这在咱们须要获取一个随机 first、middle 或 last name 时很是有用。
在个人机器(2016 MacBook Pro, 2,7 GHz Intel Core i7, 16GB RAM)上执行代码,完成任务一共花费了 3 分 32 秒。让咱们看看如何用 Node.js 工做线程来提升性能!
为了在这个简单的程序中采用多线程,咱们须要对咱们的代码进行一些修改。让咱们从 main.js
文件开始:
首先,咱们须要从 worker_threads
模块中引入 Worker
类。它容许咱们在任何须要的时候建立一个新工人(线程)。
接下来咱们能够设置要建立的线程数量:在这种状况下,我决定只建立 10 个线程。
而后咱们须要计算每一个线程须要生成名字的数量;这很简单,咱们只须要用名字的总数除以线程的数量。
对每个线程,咱们须要建立一个新的 Worker
。如你所见,这段代码将被放在 worker.js
文件。
咱们将给新的 Worker
发送一些数据来告诉它须要建立多少名字和存放在哪里(输出文件)。
咱们将一直侦听错误和退出,这样咱们就能知道在咱们的工做线程里面发生了什么事情。
如今让咱们看看 worker.js
文件作了什么:
基本上它的代码和原先的 main.js
文件同样。每当咱们存储一个新名字时,咱们会将它发送回主线程,因此它能保持对线程内部的追踪,让咱们知道里面发生了什么。
结果如何?咱们只用 1 分 24 秒完成了相同的操做!比单线程版本 快了 37%!
当你须要执行一个 CPU 密集型任务时,工做线程 是一个了不得的解决方案。它们使文件系统相关的操做更快,而且在须要执行任何类型的并发操做时帮助很大。最棒的是,如咱们前面提到的,它们在单核机器上也能工做,因此它们能在任何服务上保证更好的性能。
实际上,我已经在一个大规模的上传操做中使用了 工做线程,在那里我须要检查上百万的用户而且存储他们的数据到数据库。采用多线程的方式,操做速度比对应的单线程快了 10 倍。
我还在图片操做里使用到了 工做线程。我须要对单个图片构建三个缩略图(不一样尺寸的),在这种操做里,多线程的方式一样帮我节约了时间。
如你所见,工做线程 模块能够很好地帮助你提升性能,因此若是它在某种方式下帮助你了,请告诉我吧!