學習軌道
/
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 Worker API。正如 MDN 所述:

Web Workers 讓你能在與應用程式主要執行執行緒分開的背景執行緒中執行腳本作業。

另一方面,如果你的 JavaScript 是在 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 等語言採用的不同作法。