[Electron] 12.멀티스레딩 구현 with worker(1) - 레시피 일렉트론 앱

개요

웹 워커(Worker)로 멀티스레딩(Multithreading)을 구현할 준비를 한다. 웹 워커는 워커 스레드(Worker thread)를 따로 만들어 메인 프로세스와 별도로 검색을 처리할 예정이다.

Electron의 멀티스레딩

현재까지 구현한 것만으로도 레시피 검색 속도 및 성능은 나쁘지 않았다. 하지만 이는 레시피의 수, DB 사이즈가 작기 때문에 큰 문제를 일으키지 않는다고 볼 수 있다. 더 많은 수의 레코드 및 데이터를 다루게 된다면 단일로 돌아가는 Electron의 main process는 부하를 견디지 못할 수 있다. main에서 Sqlite DB 검색 결과를 처리할 때 까지 일렉트론 앱은 다른 작업 수행(창 위치 옮기기, 최소화, 최대화 등)을 하려 하면 ‘응답없음’ 현상을 보일 것이 뻔하다.

 

따라서 Electron Main process를 단일 스레딩이 아닌 멀티스레딩(Multithreading)으로 구현해 줄 것이다. 이를 위해 worker thread를 생성하여 검색 처럼 CPU 소요가 큰 작업은 worker thread에서 수행하도록 넘겨준다.

워커란

Web worker는 워커의 한 종류이다. 이하 워커는 모두 web worker를 지칭한다. Javascript는 기본적으로 싱글 스레드로 동작하는데, 워커는 별도의 스레드를 생성하여 멀티스레딩을 가능하도록 한다.

Electron, Node.js에서도 멀티스레딩을 위해 Web worker를 사용할 수 있다.

 

Electron 공식 docs: https://www.electronjs.org/docs/latest/tutorial/multithreading

 

Multithreading | Electron

With Web Workers, it is possible to run JavaScript in OS-level threads.

www.electronjs.org

 

현재 레시피 일렉트론 앱에서는 메인 프로세스에서 모든 로직들을 처리하고 있다. CPU 사용량이 높은 Sqlite DB 검색 로직을 Worker thread에서 처리하도록 할 것이다.

사전 설정

우선 본격적으로 worker script를 작성하고 다른 로직들을 worker에 최적화하기 전에 사전 설정을 해준다.

...
  //main.js  
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    titleBarStyle: 'hidden',
    webPreferences: {
      preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY,
      nodeIntegrationInWorker: true
    },
  });
...

main.js: 우선 worker thread에서 Node.js API를 사용할 수 있도록 설정해야한다. main.js에서 BrowserWindow 인스턴스 생성자의 인자 중 nodeIntegrationInWorker 값을 True로 설정한다. (Modal window도 함께)

 

//webpack.main.config.js
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');

module.exports = {
  /**
   * This is the main entry point for your application, it's the first file
   * that runs in the main process.
   */
  entry: {
    index: './src/main/main.js',
    worker: './src/main/worker/worker.js',
  },
  // Put your normal webpack config below here
  module: {
    rules: require('./webpack.rules'),
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, '.webpack/main'),
  },  
  plugins: [
  ],  
};

webpack.main.config.js: 아래 사항들을 통해 worker 파일의 webpack 패키징 및 번들링에 대해 설정한다.

  • entry: 일렉트론의 entry point을 설정한다. 기존에 default로 설정되어 있던, main process(main.js)를 위한 index 외에 worker entry point를 추가한다. (worker.js 경로 매핑)
  • output: 번들링된 파일의 출력 경로와 파일 이름을 설정한다. [name]은 entry 항목에서 설정한 이름(index, worker)이 된다. 기존 main process만 운용할 때는 따로 설정하지 않아도 default로 index.js가 해당 경로에 생성된다.
  • module: webpack.rules.js 파일을 통해 webpack 모듈 규칙을 가져온다.

기존에는 main process에 대한 번들 작업만 포함되어있었지만, worker에 관한 설정 또한 추가하여 worker thread를 webpack에서 사용할 수 있도록 한다.

 

 💡 번들링이란

 번들링은 여러 개의 소스 파일들을 하나 또는 여러 개의 번들 파일로 결합하는 프로세스를 말한다. Electron webpack에서는 main.js, renderer.js 등에서 import되는 모듈 등을 모두 하나로 합쳐 번들링하여 .webpack 폴더에 포함시키고 앱을 구동하는 데에 사용한다.