본문 바로가기
C++ 200제/코딩 IT 정보

Node.js Worker Threads : 스레드 간에 데이터 송수신 방법

by vicddory 2020. 3. 17.
반응형

이 포스트는 Node.js에서 진짜 스레드를 취급하는 Worker Threads 를 활용해, 스레드 간에 데이터 송수신하는 방법을 설명합니다.


이 글을 통해 알 수 있는 것

  • node.js 메인 스레드에서 Worker 로 데이터 전송 방법?
  • Worker 에서 메인 스레드에 데이터 송신 방법?
  • Worker 간의 데이터 송수신?

메인 스레드에서 Worker 로 데이터 전송 방법

메인 스레드에서 Worker 로 데이터를 송신하려면 WorkerpostMessage 함수를 사용합니다. 다음 예제는 'Hello!' 문자열 데이터를 Worker 로 보내는 것입니다.


// main.js
const {Worker= require('worker_threads')
const worker = new Worker('./worker.js')
worker.postMessage('Hello!')


Worker 가 데이터를 수신하려면 worker_threads 모듈의 parentPort 를 사용합니다. parentPort 객체에는 on 메소드가 있으며. 'message' 이벤트를 처리하는 이벤트 핸들러로

등록하면, 메인 스레드에서 데이터를 수신할 수 있습니다 :


// worker.js
const {parentPort= require('worker_threads')
parentPort.on('message'message => {
  console.log('worker received message: %o'message)
})


이 node.js 샘플 코드의 main.js 를 실행해 보면 Worker 의 데이터 수신을 확인할 수 있습니다.


$ node main.js
worker received message: 'Hello!'


Worker 에서 메인 스레드에 데이터 전송하는 방법

반대로, Worker에서 메인 스레드에 데이터를 전송하려면 parentPort 객체의 postMessage 메소드를 사용합니다. 다음 샘플 코드는 Worker 측의 코드로 메인 스레드에 문자열 'Hello!'를 보냅니다.


// worker.js
const {parentPort= require('worker_threads')
parentPort.postMessage('Hello!')


수신 측의 메인 스레드 코드는 생성된 Worker 객체의 on 메소드의 'message' 이벤트 처리용 이벤트 핸들러를 등록합니다. 이것으로 Worker 가 송신한 데이터를 수신할 수 있습니다.


// main.js
const {Worker= require('worker_threads')
const worker = new Worker('./worker.js')
worker.on('message'message => {
  console.log('Main thread received message: %o'message)
})

Worker 간의 데이터 송수신 방법

Worker A에서 Worker B로 데이터를 전송하려면 메인 스레드가 송수신을 중계해 줄 필요가 있습니다.


먼저, 데이터 발신자 Worker 가 node.js 메인 스레드로 데이터를 보냅니다.


// worker1.js
const {parentPort= require('worker_threads')
parentPort.postMessage('message from worker1')


다음, 데이터를 받는 Worker는 메인 스레드에서 데이터를 수신합니다.


// worker2.js
const {parentPort= require('worker_threads')
parentPort.on('message'message => {
  console.log('worker2 received message: %o'message)
})


마지막으로, Worker 2개의 데이터 송수신을 중계하는 코드를 메인 스레드에 구현합니다.


// main.js
const {Worker= require('worker_threads')
const worker1 = new Worker('./worker1.js')
const worker2 = new Worker('./worker2.js')
worker1.on('message'message => worker2.postMessage(message))


이 main.js 를 실행하면 두 Worker간에 데이터 송수신이 된다는 것을 확인할 수 있습니다.


$ node main.js
worker2 received message: 'message from worker1'

MessageChannel 을 사용한 Worker 간 데이터 송수신

위의 예시에선 메인 스레드가 메시지를 중계합니다. 이 방법으로 Worker 간 데이터 송수신을 구현했습니다.


Worker 간에서 데이터 송수신하는 다른 방법으론 node.js MessageChannel 활용이 있습니다.


메인 측에서 MessageChannel 을 만들 때 MessagePort 2개가 생성됩니다. 각각을 각 Worker 에 전달하도록 합니다.


// main.js
const {WorkerMessageChannel= require('worker_threads')
const {port1port2= new MessageChannel()
const worker1 = new Worker('./worker1.js')
const worker2 = new Worker('./worker2.js')
worker1.postMessage({worker2port1}, [port1])
worker2.postMessage({worker1port2}, [port2])


MessagePort 를 받은 Worker 는 이후 MessagePort 를 통해 Worker 간 데이터 송수신을 할 수 있게 됩니다.


// worker1.js
const assert = require('assert')
const {parentPortMessagePort= require('worker_threads')
parentPort.once('message', ({worker2}) => {
  assert(worker2 instanceof MessagePort)
  worker2.postMessage('message from worker1')
})


// worker2.js
const assert = require('assert')
const {parentPortMessagePort= require('worker_threads')
parentPort.once('message', ({worker1}) => {
  assert(worker1 instanceof MessagePort)
  worker1.on('message'message => {
    console.log('worker2 received message: %o'message)
  })
})


정리

  • 메인 스레드에서 Worker 데이터를 전송할 때, worker.postMessage 호출, Worker 는 parentPort.on('message', ...)에서 이벤트 핸들링.
  • Worker 에서 메인 스레드에 데이터를 송신할 때, Worker 는 parentPort.postMessage 호출, 메인 스레드 측은 worker.on('message', ...)에서 이벤트 핸들링.
  • Worker 간의 데이터 송수신은 메인 스레드 중계 또는 MessageChannel 응용.



반응형