티스토리 뷰

목차

    반응형

    이 포스트는 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 응용.



    반응형