![](https://t1.daumcdn.net/cfile/tistory/99B60B345E6DDCCB2B)
이 포스트는 Node.js에서 진짜 스레드를 취급하는 Worker Threads 를 활용해, 스레드 간에 데이터 송수신하는 방법을 설명합니다.
이 글을 통해 알 수 있는 것
- node.js 메인 스레드에서 Worker 로 데이터 전송 방법?
- Worker 에서 메인 스레드에 데이터 송신 방법?
- Worker 간의 데이터 송수신?
메인 스레드에서 Worker 로 데이터 전송 방법
메인 스레드에서 Worker 로 데이터를 송신하려면 Worker 의 postMessage 함수를 사용합니다. 다음 예제는 '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 {Worker, MessageChannel} = require('worker_threads')
const {port1, port2} = new MessageChannel()
const worker1 = new Worker('./worker1.js')
const worker2 = new Worker('./worker2.js')
worker1.postMessage({worker2: port1}, [port1])
worker2.postMessage({worker1: port2}, [port2])
MessagePort 를 받은 Worker 는 이후 MessagePort 를 통해 Worker 간 데이터 송수신을 할 수 있게 됩니다.
// worker1.js
const assert = require('assert')
const {parentPort, MessagePort} = require('worker_threads')
parentPort.once('message', ({worker2}) => {
assert(worker2 instanceof MessagePort)
worker2.postMessage('message from worker1')
})
// worker2.js
const assert = require('assert')
const {parentPort, MessagePort} = 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 응용.