WbMango의 파이썬

"초보자를 위한 파이썬 강의부터 실무 팁까지! 실력 향상에 도움이 되는 실전 콘텐츠 제공."

  • 2025. 3. 20.

    by. wbmango

    목차

      파이썬 성능 향상을 위한 병렬 프로그래밍 실습 (Joblib, multiprocessing)

       

      1. 파이썬 병렬 프로그래밍이란? 그리고 왜 필요한가?

      소프트웨어 개발에서 **성능 최적화(Performance Optimization)**는 매우 중요한 요소입니다. 특히, 데이터 분석, 머신러닝, 대규모 시뮬레이션, 웹 애플리케이션과 같이 고속 연산이 필요한 작업에서는 실행 속도를 최적화하는 것이 필수적입니다. 현대 프로세서는 멀티코어(Multi-core) 아키텍처를 채택하고 있으며, 이를 효과적으로 활용하기 위해 **병렬 프로그래밍(Parallel Programming)**이 요구됩니다.

      📍 병렬 프로그래밍이란?

      병렬 프로그래밍은 여러 개의 작업을 동시에 수행하여 실행 속도를 개선하는 기법입니다. 기존의 프로그래밍 방식은 대부분 하나의 작업을 순차적으로 수행하는 직렬(Serial) 방식이었습니다. 그러나 컴퓨터의 하드웨어 성능이 발전하면서, 다중 작업을 동시에 실행할 수 있는 병렬(Parallel) 방식이 필요하게 되었습니다.

       

      📍 파이썬에서 병렬 프로그래밍이 필요한 이유

      파이썬은 직관적이고 간결한 문법 덕분에 데이터 처리 및 AI 분야에서 널리 사용되지만, 전통적인 싱글 스레드(Single Thread) 실행 방식으로 인해 성능이 제한될 수 있습니다.
      이러한 문제를 해결하기 위해, 파이썬에서는 멀티프로세싱(multiprocessing)과 멀티스레딩(multithreading) 기법을 활용하여 성능을 최적화할 수 있습니다.

       

      📌 예제: 병렬 처리를 활용하면 어떤 작업이 빨라질까?

      • 대용량 데이터 처리: 수백만 개의 데이터를 처리하는 경우
      • 머신러닝 모델 학습: 여러 개의 하이퍼파라미터 조합을 테스트하는 경우
      • 웹 크롤링: 다수의 웹페이지를 동시에 크롤링하는 경우
      • 이미지 및 영상 처리: 여러 개의 이미지를 동시에 분석하는 경우

       

      이 글에서는 파이썬에서 병렬 프로그래밍을 구현하는 방법을 심층적으로 살펴보고, 특히 multiprocessing 및 Joblib을 활용하여 코드 실행 속도를 획기적으로 향상시키는 방법을 소개하겠습니다.


      2. 파이썬 병렬 프로그래밍의 핵심 개념과 기법

      📍 병렬 프로그래밍과 GIL(Global Interpreter Lock)의 관계

      파이썬에서 병렬 프로그래밍을 제대로 이해하려면 먼저 **GIL(Global Interpreter Lock)**에 대한 개념을 알아야 합니다. GIL은 파이썬 인터프리터가 한 번에 하나의 스레드만 실행하도록 제한하는 메커니즘입니다. 즉, 멀티스레딩을 사용하더라도 한 순간에 하나의 작업만 실행되기 때문에 GIL이 적용된 환경에서는 멀티스레딩이 성능 향상에 큰 도움을 주지 못하는 경우가 많습니다.

      파이썬의 GIL은 메모리 관리 및 쓰레드 간 충돌을 방지하는 역할을 하지만, CPU 연산이 많은 작업(예: 수학 연산, 이미지 처리, 머신러닝 모델 학습 등)에서는 성능 저하를 초래할 수 있습니다. 따라서 GIL의 영향을 피하기 위해 멀티프로세싱(multiprocessing)을 활용하는 것이 권장됩니다.

       

      📍 멀티프로세싱 vs 멀티스레딩

      멀티프로세싱과 멀티스레딩은 모두 병렬 처리를 수행하는 방법이지만, 작동 방식과 성능 향상 효과는 다릅니다.

      방식 개념 장점 단점
      멀티프로세싱 여러 개의 프로세스를 생성하여 독립적인 작업 수행 GIL 영향을 받지 않음, CPU 코어 활용 극대화 프로세스 간 통신 비용이 발생
      멀티스레 하나의 프로세스 내에서 여러 개의 스레드를 실행 메모리 공유가 용이, I/O 작업에 효과적 GIL 때문에 CPU 연산 작업에서는 성능 향상 제한

       

      멀티스레딩은 I/O 바운드 작업(예: 파일 읽기, 네트워크 요청, 데이터베이스 질의)에서는 효과적이지만, CPU 바운드 작업(예: 행렬 연산, 머신러닝 모델 학습, 이미지 처리)에서는 GIL 때문에 멀티프로세싱이 훨씬 더 좋은 성능을 제공합니다.

      이제 본격적으로 멀티프로세싱을 활용한 병렬 프로그래밍을 실습해보겠습니다.

       

       


      3. 실습 ① 파이썬 multiprocessing을 활용한 병렬 프로그래밍

      📍 1. 파이썬 multiprocessing 모듈 기본 예제

      아래는 multiprocessing을 활용하여 멀티프로세싱을 적용하는 간단한 예제입니다.

      import multiprocessing
      import time
      
      def worker(num):
          print(f"프로세스 {num} 시작")
          time.sleep(2)
          print(f"프로세스 {num} 완료")
      
      if __name__ == "__main__":
          processes = []
          
          for i in range(4):  # 4개의 프로세스 생성
              p = multiprocessing.Process(target=worker, args=(i,))
              processes.append(p)
              p.start()
      
          for p in processes:
              p.join()
          
          print("모든 작업 완료")

      🔹 실행 결과:
      4개의 프로세스가 동시에 실행되며, 실행 시간이 대폭 단축됩니다.

       

      이 코드를 실행하면 각 프로세스가 독립적으로 실행되며, 동시에 실행되는 것을 확인할 수 있습니다.

       

      📍 2. 파이썬 multiprocessing을 활용한 대용량 데이터 처리

      병렬 프로그래밍은 특히 대량의 데이터를 처리하는 경우 성능 향상 효과가 매우 큽니다. 예를 들어, 100만 개 이상의 데이터를 처리하는 작업을 병렬화하면 실행 시간을 크게 줄일 수 있습니다.

      import multiprocessing
      import numpy as np
      import time
      
      def square(num):
          return num ** 2
      
      if __name__ == "__main__":
          data = np.arange(1, 1000000)  # 100만 개 데이터 생성
          start_time = time.time()
          
          with multiprocessing.Pool(processes=4) as pool:
              result = pool.map(square, data)
          
          print(f"병렬 처리 완료! 실행 시간: {time.time() - start_time:.2f} 초")

      위 코드를 실행하면 multiprocessing.Pool()을 활용하여 각 데이터를 여러 개의 프로세스로 분할하여 처리하므로 실행 속도가 크게 향상됩니다.


       

      4. 실습 ② 파이썬 Joblib을 활용한 병렬 프로그래밍

      📍 1. Joblib이란?

      Joblib은 multiprocessing보다 더 간단하게 병렬 프로그래밍을 구현할 수 있도록 도와주는 라이브러리입니다.
      특히, 머신러닝 모델 학습, 데이터 전처리, 대규모 행렬 연산 등의 작업에서 많이 사용됩니다.

       

      📍 2. Joblib의 주요 특징

      • 더 직관적인 코드: multiprocessing보다 코드가 간결
      • 자동 캐싱 기능 지원: 동일한 연산을 여러 번 수행하는 경우 결과를 캐싱하여 성능 최적화
      • 병렬 처리 최적화: n_jobs를 설정하여 원하는 만큼 CPU 코어를 활용 가능

      📍 3. Joblib을 활용한 병렬 처리 예제

      아래는 Joblib을 사용하여 리스트 데이터를 병렬로 처리하는 코드입니다.

      from joblib import Parallel, delayed
      import time
      
      def task(n):
          time.sleep(2)
          return n ** 2
      
      start_time = time.time()
      
      results = Parallel(n_jobs=4)(delayed(task)(i) for i in range(10))
      
      print(f"결과: {results}")
      print(f"총 실행 시간: {time.time() - start_time:.2f} 초")

      이 코드에서는 n_jobs=4로 설정하여 4개의 CPU 코어를 활용하여 병렬 실행합니다.

      🔹 실행 결과:
      multiprocessing과 유사하지만 코드가 더 간결하며, 병렬 처리를 더욱 쉽게 구현할 수 있습니다.

       

      📍 4. Joblib과 파이썬 머신러닝 모델 학습 최적화 실습

      Joblib은 특히 머신러닝 모델의 학습을 병렬화하는 데 유용합니다.
      아래 예제에서는 여러 개의 머신러닝 모델을 병렬로 학습하는 방법을 보여줍니다.

      from joblib import Parallel, delayed
      from sklearn.ensemble import RandomForestClassifier
      from sklearn.datasets import make_classification
      from sklearn.model_selection import train_test_split
      
      # 데이터 생성
      X, y = make_classification(n_samples=10000, n_features=20, random_state=42)
      X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
      
      # 병렬 학습 함수
      def train_model(n_estimators):
          model = RandomForestClassifier(n_estimators=n_estimators, n_jobs=-1)
          model.fit(X_train, y_train)
          return model.score(X_test, y_test)
      
      # 5개의 다른 모델을 병렬로 학습
      results = Parallel(n_jobs=5)(delayed(train_model)(n) for n in [10, 50, 100, 200, 500])
      
      print(f"모델 정확도: {results}")

      위 코드를 실행하면, 각 모델이 병렬로 학습되어 학습 시간이 단축됩니다.