멀티 프로세싱

Jane Yeonju Kim·2022년 12월 27일
0
post-thumbnail
post-custom-banner

파이썬

multiprocessing 모듈

한글로 되어있는 파이썬 모듈 공식 문서
Process 객체를 만들고 start()로 프로세스를 spawning합니다.

Spawn: to cause something new, or many new things, to grow or start suddenly

Spawn은 부모 프로세스가 새로운 프로세스를 생성하는 것을 말합니다. 내부적으로 run() 메서드를 실행합니다. run() 메서드를 호출할 때 필요한 리소스들을 상속받기 때문에 fork, forkServer로 생성하는 것보다는 상대적으로 느리지만 안전합니다. Process의 서브클래스를 만드려면 run() 메서드를 오버라이딩해야 합니다.

쓰레드가 아닌 프로세스기 때문에 Global Interpreter Lock(파이썬 멀티쓰레드의 한계..)로 부터 자유롭습니다! 프로세스와 쓰레드의 차이는 10분 테코톡 - Process vs Thread 영상에서 친절한 설명을 들을 수 있습니다.

join()메서드는 하부 프로세스가 종료될 때까지 block시키는 메서드입니다. 이 메서드를 사용해서 메인 프로세스에서 하부 프로세스가 끝날때까지 기다려줄 수 있습니다. 만약 하부 프로세스가 끝나지 않았더라도 메인 프로세스 종료시 같이 종료시키려면 Process 객체 생성시 daemon= True 옵션을 주면 됩니다.

프로세스를 종료시키고 자원을 해제하는 메서드는 close()가 있고, 큐나 파이프가 손상될 위험때문에 terminate(), kill() 메서드는 사용하지 않는 것이 좋습니다.

from multiprocessing import Process
import os

def info(title):
    print(title)
    print('module name:', __name__)
    print('parent process:', os.getppid())
    print('process id:', os.getpid())

# 프로세스의 args를 받아서 target인 f함수를 실행합니다.
def f(name):
    info('function f')
    print('hello', name)

if __name__ == '__main__':
    info('main line')
    # 프로세스 객체 생성
    p = Process(target=f, args=('bob',))
    # 프로세스 spawning
    p.start()
    # 프로세스 block
    p.join()

프로세스 간 객체를 공유하는 방법은 Queue, Pipe의 두 가지 방법이 있습니다.

  • Queue : 여러 프로세스가 객체를 큐에 넣는 경우, 반대편에서 객체가 다른 순서로 수신될 수 있습니다. 그러나, 같은 프로세스에 의해 큐에 들어간 객체들은 항상 상대적인 순서가 유지됩니다.
from multiprocessing import Process, Queue

def f(q):
    q.put([42, None, 'hello'])

if __name__ == '__main__':
    q = Queue()
    # args에 생성한 Queue를 넘겨서 공유합니다.
    p = Process(target=f, args=(q,))
    p.start()
    # q.put() 과 q.get() 메서드로 큐에 넣거나 값을 읽어올 수 있습니다.
    print(q.get())    # prints "[42, None, 'hello']"
    p.join()
  • Pipe : 양방향, 단방향(consumer, producer 순서)을 정할 수도 있습니다.
from multiprocessing import Process, Pipe

def f(conn):
    conn.send([42, None, 'hello'])
    conn.close()

if __name__ == '__main__':
    # Pipe()는 파이프의 끝을 나타내는 Connection 객체 쌍 (conn1, conn2) 를 반환합니다.
    parent_conn, child_conn = Pipe()
    p = Process(target=f, args=(child_conn,))
    p.start()
    # send()와 recv() 메서드로 파이프에 한쪽 끝에 객체를 넣고 다른 끝으로 반환합니다.
    print(parent_conn.recv())   # prints "[42, None, 'hello']"
    p.join()

노드

Worker Threads

자바스크립트는 싱글 스레드로 실행되지만 노드는 실제로 병렬로 실행됩니다. 언어 자체가 싱글 스레드이기 때문에 사실 병렬 작업보다는 CPU 집약적인 작업을 위해서 사용하는 방법들이 있습니다.
노드 10.5.0 버전 이후부터는 worker_threads가 이용 가능합니다.
worker_threads의 각각의 worker는 각자의 V8 인스턴스와 Event Loop를 가지게 됩니다. 그렇지만 child process나 cluster 모듈과는 다르게 메모리를 공유할 수 있습니다. ArrayBuffer 인스턴스를 전달하거나 SharedArrayBuffer 인스턴스를 공유하는 방법을 통해 가능합니다.

출처: LITSLINK사의 Node.js Architecture from A to Z


Web Worker API

Web Worker API는 백그라운드 스레드에서 스크립트를 실행하는 방법입니다. Worker는 현재의 window와는 다른 글로벌 컨텍스트에서 실행됩니다.
Worker와 메인 스레드 사이에서는 메시지 시스템을 통해 데이터를 발송합니다. 양쪽 모두 postMessage() 메서드를 사용하여 메시지를 발송하고, onmessage이벤트 핸들러에 의해 메시지에 응답합니다. 데이터는 공유되지 않고 복사됩니다.
노드 12.17.0 버전부터 이용 가능합니다.





참고한 글들
Python multiprocessing.Process 멀티프로세싱 1
nodejs의 멀티쓰레딩과 worker threads
노드 공식문서 worker_threads
MDN - Web Workers API
Deep Dive into Worker Threads in Node.js

profile
안녕하세요! 김개발자입니다 👩‍💻 🐈
post-custom-banner

0개의 댓글