轨道
/
JavaScript
JavaScript
/
练习
/
并行字母频率
并行字母频率

并行字母频率

中等

说明

使用并行计算统计文本中字母的频率。

并行是指把那些同样可以顺序完成的事情并行地做。一个常见的例子就是统计字母的频率。利用并行计算来算出文本数组中每个字母的总频率。

JavaScript 天生就是单线程的,因此缺少其他语言为处理并行代码执行而具备的许多语言特性。 事实上,想要实现“真正的”并行代码执行,唯一的途径就是使用 Worker threads(也叫 Web Workers)。

大多数时候,看起来像是在并行执行的代码,比如async functions或Promises,实际上都是并发执行的。 这通常更好,因为现代 JavaScript 正是为这种用法做了优化。你也经常会看到一些代码借助Promise.all()以及其他并发执行的方法来“模拟”(或者说“取巧”实现)并行执行。

To pass the tests for this exercise, your solution needs to execute _concurrently_ (or in parallel),
meaning that synchronous solutions (e.g. a simple `for` loop) will not pass.

并发与并行

下面用简短的定义来说明两者的区别:

  • 并发:两个或多个任务可以在相互重叠的时间段内启动、运行和完成,由同一个处理单元执行。
  • 并行:两个或多个任务可以同时启动和运行,由不同的处理单元各自独立执行。

为了完整起见,这里再给出同步执行的定义:

  • 同步执行:一个任务必须等待另一个正在运行的任务完成后,才能开始运行。

JavaScript 中的并行

虽然 JavaScript 默认是单线程的,但仍然有办法以并行的方式执行代码。

如果你是在浏览器中运行 JavaScript(例如在 Web 应用里),那么实现并行的方式就是使用 Web Worker API。 正如 MDN 所说:

Web Workers 让脚本操作可以在后台线程中运行,与应用程序的主执行线程分离。

另一方面,如果你的 JavaScript 运行在 Node.js 中(Node.js 也是 Exercism 的目标运行时),同一个概念叫做 Worker threads。

Be aware that the implementation of the worker API differs largely between browsers and other JavaScript environments.

Make sure to read the documentation for your specific runtime!

下面是一个 Web Worker API 的简单示例(摘自 Medium)

// main.js
const myWorker = new Worker('worker.js');

myWorker.postMessage(5);

myWorker.onmessage = function (event) {
  console.log('Received result from worker:', event.data);
};
// worker.js
onmessage = function (event) {
  console.log('Received number from main thread:', event.data);

  // Perform computation
  const result = event.data * 2;

  // Send result back to the main thread
  postMessage(result);
};

下面是 Worker threads API 的示例(摘自文档)

const {
  Worker,
  isMainThread,
  parentPort,
  workerData,
} = require('node:worker_threads');

if (isMainThread) {
  module.exports = function parseJSAsync(script) {
    return new Promise((resolve, reject) => {
      const worker = new Worker(__filename, {
        workerData: script,
      });
      worker.on('message', resolve);
      worker.on('error', reject);
      worker.on('exit', (code) => {
        if (code !== 0)
          reject(new Error(`Worker stopped with exit code ${code}`));
      });
    });
  };
} else {
  const { parse } = require('some-js-parsing-library');
  const script = workerData;
  parentPort.postMessage(parse(script));
}
Currently it is not possible to implement parallelism using the online editor.

Please implement `Worker threads` using Node.js locally and submit your solution via CLI!

作为进阶目标,可以考虑能否调整你的实现来使用 Worker threads。


延伸阅读

通过 GitHub 编辑 链接将在新窗口或新标签页中打开
JavaScript Exercism

准备好开始 并行字母频率 了吗?

注册 Exercism,借助 37 个概念159 个练习 和真人导师指导,学习并掌握 JavaScript,全部免费。

深入探索 并行字母频率!

我们探讨并发与并行之间的区别,并看看 JavaScript、Go、Elixir 和 Rust 等语言采用的不同做法。