기본 콘텐츠로 건너뛰기

추천 가젯

리액트 + 비트(Vite)로 모바일 청첩장 만들기 — 1편

모바일 청첩장 시리즈 1편 · 기획/스택/배포 리액트 + 비트(Vite)로 모바일 청첩장 만들기 — 1편 안녕하세요, 이번에 결혼 준비를 하면서 여자친구와 같이 모바일 청첩장 을 만들고 있어요. 여자친구가 디자인을 해서 전달해주면 제가 개발을 진행하고 있어요. 이 글은 구현기 1편 으로, 전체 흐름과 스택, 배포 구성까지 “부담 없이” 훑어봅니다. (코드는 여러 버전 테스트 중!) 이 글에서 보는 것 왜 SPA 모바일 청첩장인가? 기본 스택 & 폴더 구조 라우팅 선택: HashRouter가 편한 이유 Cloudflare Pages로 자동 배포 현재 진행 중인 UI 버전들(테스트 기록) 1) 왜 SPA 모바일 청첩장인가? 모바일 청첩장은 핵심이 명확해요. 가볍고 빠르고 끊김이 없어야 하고, 사진/지도/일정이 터치에 친화적 이어야 합니다. 그래서 React + Vite 로 싱글 페이지 앱(SPA)을 구성했고, 정적 호스팅(CDN)인 Cloudflare Pages 에 올려 GitHub 푸시 → 자동 배포 까지 한 번에 묶었습니다. UX 팁 · 이미지 WebP, loading="lazy" 기본 · 큰 터치 타깃 · BGM은 “사용자 탭 후” 재생(모바일 정책) 2) 기본 스택 & 폴더 구조 서버는 따로 두지 않았고, 정적 빌드 결과물( dist/ )만 올립니다. 현재 의존성은 아래와 같아요. package.json(요약) { "name": ...

🚀 multiprocessing으로 CPU 병렬 처리 쉽게 구현하기

Multiprocessing icon

🚀 multiprocessing으로 CPU 병렬 처리 쉽게 구현하기

multiprocessing 모듈은 멀티코어 CPU를 활용한 병렬 프로세싱을 가능하게 해 줍니다. 스레드와는 달리 **GIL의 제약 없이** 완전한 병렬 처리를 수행할 수 있어 CPU 바운드 작업에 최적입니다.

✅ 1. `Process`로 직접 프로세스 생성하기

from multiprocessing import Process
import os

def worker(num):
    print(f"프로세스 {num} 시작, PID={os.getpid()}")

if __name__ == '__main__':
    procs = [Process(target=worker, args=(i,)) for i in range(4)]
    for p in procs:
        p.start()
    for p in procs:
        p.join()
  • 각 `Process`는 독립된 메모리 공간을 가지고 실행됩니다.
  • `join()`을 통해 각 프로세스 종료를 기다릴 수 있습니다.

✅ 2. `Pool`을 활용한 작업 분산 처리

from multiprocessing import Pool

def fib(n):
    return n if n < 2 else fib(n-1) + fib(n-2)

if __name__ == '__main__':
    with Pool(processes=4) as pool:
        results = pool.map(fib, [20, 22, 24, 26])
    print(results)
  • `Pool.map()`은 입력 값을 자동으로 분할해 병렬 계산합니다.
  • CPU 병렬화로 재귀 계산이 빠르게 완료됩니다.

✅ 3. `Queue`로 서로 다른 프로세스 간 통신하기

from multiprocessing import Process, Queue

def producer(q):
    for val in ['A','B','C']:
        q.put(val)
    q.put(None)

def consumer(q):
    while True:
        item = q.get()
        if item is None:
            break
        print("소비:", item)

if __name__ == '__main__':
    q = Queue()
    p1 = Process(target=producer, args=(q,))
    p2 = Process(target=consumer, args=(q,))
    p1.start(); p2.start()
    p1.join(); p2.join()
  • 프로세스 간 안전한 데이터 전달, `None`과 같은 종료 시그널 사용 권장.
  • Queue는 내부적으로 립-싱크(lock) 처리를 자동 수행합니다.

✅ 4. `Manager()`로 공유 메모리 값 다루기

from multiprocessing import Manager, Process

def worker(d, l, key, value):
    d[key] = value
    l.append(key)

if __name__ == '__main__':
    mgr = Manager()
    shared_dict = mgr.dict()
    shared_list = mgr.list()
    procs = [Process(target=worker, args=(shared_dict, shared_list, i, i*10)) for i in range(5)]
    for p in procs:
        p.start()
    for p in procs:
        p.join()
    print(shared_list)
    print(shared_dict)
  • 복수 값 공유 및 동시 수정이 필요할 때 유용.
  • 하지만 느릴 수 있으므로 빈번한 접근은 피하세요.

✅ 5. 성능 비교: `map` vs `Pool` vs 단일 함수

import timeit, multiprocessing

setup = """
from multiprocessing import Pool
def heavy(x):
    s = 0
    for i in range(1000000):
        s += i*x
    return s
data = range(4)
"""

t_single = timeit.timeit("list(map(heavy, data))", setup=setup, number=10)
t_pool = timeit.timeit("""
with Pool(processes=4) as p:
    p.map(heavy, data)
""", setup=setup + "\nfrom multiprocessing import Pool", number=10)

print("단일 프로세스:", t_single)
print("Pool 병렬 처리:", t_pool)
  • CPU 바운드 작업 시 `Pool` 사용이 압도적으로 빠름!
  • 작업 단위가 작을 경우 오버헤드가 커질 수 있으니 **적절한 블록 사이즈** 고려하세요.

✨ 요약 & 활용 팁

  • GIL 제약 없이 진정한 병렬 처리 가능 → CPU 바운드 작업에 적합
  • 작업 자동 분배가 필요한 경우 `Pool`이 가장 쉽고 효과적
  • 프로세스 간 통신은 `Queue`, `Manager`로 안전하게 수행할 수 있음
  • 데이터 공유 구조는 편하지만 성능 저하 고려 필요
  • 작업 크기와 프로세스 개수는 벤치마크로 최적화하세요

댓글

가장 많이 본 글

Icons by Flaticon