기본 콘텐츠로 건너뛰기

Python에서 멀티프로세싱을 사용하는 실전 예제

개요

Python에서 멀티프로세싱을 활용하면 CPU 바운드 작업의 처리 속도를 획기적으로 향상시킬 수 있습니다. 단일 코어만 사용하는 싱글 스레드 방식과 달리, 멀티프로세싱은 여러 코어를 활용하여 병렬 처리를 가능하게 하므로, 특히 CPU 사용률이 높은 작업에 효과적입니다. 이 포스트에서는 실제 코드 예제를 통해 Python의 multiprocessing 모듈을 사용하는 방법과 주의사항을 알아보겠습니다.

핵심 개념 정리

Python의 multiprocessing 모듈은 프로세스 생성 및 관리를 위한 다양한 기능을 제공합니다. 핵심 클래스는 Process이며, 이를 이용해 새로운 프로세스를 생성하고, target 인자로 실행할 함수를 지정합니다. argskwargs 인자를 통해 함수에 인자를 전달할 수 있습니다. Pool 클래스는 여러 프로세스를 효율적으로 관리하는 데 유용하며, map, apply_async 등의 메서드를 통해 병렬 처리 작업을 수행할 수 있습니다.

실전 코드 예제

다음은 CPU 바운드 작업인 소수 판별을 멀티프로세싱으로 구현한 예제입니다. is_prime 함수가 소수 판별 로직을 담고 있으며, multiprocessing.Pool을 사용하여 여러 프로세스에서 병렬적으로 실행합니다.

import multiprocessing
import time

def is_prime(n):
    if n <= 1:
        return False
    for i in range(2, int(n**0.5) + 1):
        if n % i == 0:
            return False
    return True

if __name__ == '__main__':
    numbers = list(range(100000)) # 판별할 숫자 리스트
    start_time = time.time()

    # 싱글 스레드 방식
    single_result = list(map(is_prime, numbers))
    single_time = time.time() - start_time
    print(f"Single-threaded time: {single_time:.4f} seconds")


    start_time = time.time()
    with multiprocessing.Pool(processes=multiprocessing.cpu_count()) as pool:
        multi_result = pool.map(is_prime, numbers)
    multi_time = time.time() - start_time
    print(f"Multi-processed time: {multi_time:.4f} seconds")

    # 결과 확인 (생략 가능)
    #assert single_result == multi_result

코드 실행 결과, 멀티프로세싱 방식이 싱글 스레드 방식보다 훨씬 빠르게 처리되는 것을 확인할 수 있습니다. multiprocessing.cpu_count()는 시스템의 CPU 코어 수를 자동으로 감지하여 적절한 프로세스 수를 설정합니다.

주의사항 또는 실무 팁

  • GIL (Global Interpreter Lock): Python의 GIL은 한 번에 하나의 스레드만 Python 바이트코드를 실행하도록 제한합니다. 따라서 I/O 바운드 작업에는 멀티스레딩이 효과적일 수 있지만, CPU 바운드 작업에는 멀티프로세싱이 훨씬 효율적입니다.
  • 프로세스 생성 오버헤드: 프로세스 생성에는 시간이 소요됩니다. 작업의 크기가 작다면 오버헤드가 처리 시간보다 클 수 있으므로, 멀티프로세싱이 오히려 느릴 수 있습니다. 작업 크기와 프로세스 수를 적절히 조절해야 합니다.
  • 공유 메모리: 프로세스 간 데이터 공유는 주의가 필요합니다. multiprocessing.Value, multiprocessing.Array, multiprocessing.Manager 등을 사용하여 안전하게 데이터를 공유할 수 있습니다.
  • 에러 핸들링: 예외 처리를 철저히 하여 프로세스가 비정상 종료되는 것을 방지해야 합니다.

결론 또는 마무리 조언

Python의 멀티프로세싱은 CPU 바운드 작업의 성능을 크게 향상시키는 강력한 도구입니다. 하지만 GIL과 프로세스 생성 오버헤드 등을 고려하여 작업의 특성에 맞게 적절히 활용해야 합니다. 이 포스트에서 소개한 예제 코드와 주의사항을 참고하여 여러분의 프로그램 성능을 개선해 보세요.

댓글

이 블로그의 인기 게시물

Django에서 트랜잭션 관리하기

Django에서 트랜잭션 관리하기 안녕하세요! 오늘은 Django에서 데이터베이스 트랜잭션을 효과적으로 관리하는 방법에 대해 알아보겠습니다. 1. 트랜잭션의 중요성 트랜잭션은 데이터베이스의 일관성과 무결성을 보장하는 중요한 개념입니다. Django에서는 여러 가지 방법으로 트랜잭션을 관리할 수 있습니다. 1.1 기본 개념 원자성(Atomicity) : 트랜잭션은 모두 실행되거나 모두 실행되지 않아야 합니다. 일관성(Consistency) : 트랜잭션 전후로 데이터베이스의 일관성이 유지되어야 합니다. 격리성(Isolation) : 동시에 실행되는 트랜잭션들이 서로 영향을 주지 않아야 합니다. 지속성(Durability) : 완료된 트랜잭션의 결과는 영구적으로 저장되어야 합니다. 2. Django의 트랜잭션 관리 2.1 기본 설정 # settings.py DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'mydatabase', 'USER': 'myuser', 'PASSWORD': 'mypassword', 'HOST': 'localhost', 'PORT': '5432', 'ATOMIC_REQUESTS': True, # 모든 뷰를 트랜잭션으로 래핑 } } 2.2 데코레이터 사용 from django.db import transaction @transaction.atomic def create_order(user, items): order = Order.objects.create(user=...

AWS S3 + CloudFront로 정적 파일 서빙 완전 가이드

AWS S3 + CloudFront로 정적 파일 서빙 완전 가이드 안녕하세요! 오늘은 AWS S3와 CloudFront를 사용하여 정적 파일을 효율적으로 서빙하는 방법에 대해 알아보겠습니다. 왜 S3와 CloudFront를 사용할까요? 높은 가용성 : AWS의 글로벌 인프라를 활용 빠른 전송 속도 : CloudFront의 CDN 기능으로 전 세계 사용자에게 빠른 전송 비용 효율성 : 사용한 만큼만 지불 보안 : AWS의 보안 기능 활용 확장성 : 트래픽 증가에 자동 대응 1. S3 버킷 설정 1.1 버킷 생성 및 설정 import boto3 def create_s3_bucket(): s3 = boto3.client('s3') # 버킷 생성 bucket_name = 'your-static-files-bucket' s3.create_bucket( Bucket=bucket_name, CreateBucketConfiguration={ 'LocationConstraint': 'ap-northeast-2' } ) # 버킷 정책 설정 bucket_policy = { "Version": "2012-10-17", "Statement": [ { "Sid": "PublicReadGetObject", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObje...

RDS에서 Django 앱 성능을 높이는 데이터베이스 설정 팁

RDS에서 Django 앱 성능을 높이는 데이터베이스 설정 팁 안녕하세요! 오늘은 AWS RDS를 사용하는 Django 애플리케이션의 성능을 최적화하는 방법에 대해 알아보겠습니다. 1. RDS 인스턴스 최적화 1.1 인스턴스 타입 선택 # RDS 인스턴스 크기 조정 import boto3 def resize_rds_instance(): rds = boto3.client('rds') response = rds.modify_db_instance( DBInstanceIdentifier='your-db', DBInstanceClass='db.t3.large', # 워크로드에 맞는 인스턴스 타입 선택 ApplyImmediately=True ) return response['DBInstance'] 1.2 파라미터 그룹 설정 def create_parameter_group(): rds = boto3.client('rds') # PostgreSQL 파라미터 그룹 생성 response = rds.create_db_parameter_group( DBParameterGroupName='django-optimized', DBParameterGroupFamily='postgres13', Description='Optimized parameters for Django applications' ) # 성능 관련 파라미터 설정 parameters = [ { 'ParameterName': 'shared_buffers', 'ParameterValue': '2GB...