Post

파이썬 고급 문법: 병렬 처리와 비동기 프로그래밍

병렬 처리와 비동기 프로그래밍의 개념과 활용 방법

현대 프로그램에서는 속도를 높이고 성능을 최적화하기 위해 병렬 처리비동기 프로그래밍이 필수적입니다. 파이썬은 multiprocessing, concurrent.futures, asyncio 등을 통해 효율적인 작업 처리를 지원합니다. 이번 글에서는 병렬 처리와 비동기 프로그래밍의 개념과 활용 방법을 살펴보겠습니다.

1. 병렬 처리란?

  • 병렬 처리(Parallel Processing): 여러 작업을 동시에 실행하여 작업 시간을 단축하는 방식.
  • 파이썬에서는 멀티프로세싱(Multiprocessing)을 통해 CPU 코어를 활용한 병렬 처리가 가능합니다.

2. 멀티프로세싱

파이썬의 multiprocessing 모듈은 여러 프로세스를 생성하여 작업을 병렬로 실행할 수 있도록 지원합니다.

1) 기본 사용법

1
2
3
4
5
6
7
8
9
10
from multiprocessing import Process

def print_numbers():
    for i in range(5):
        print(f"Number: {i}")

if __name__ == "__main__":
    process = Process(target=print_numbers)
    process.start()
    process.join()

2) 프로세스 풀(Pool)

  • 프로세스 풀을 사용하면 여러 작업을 효율적으로 병렬 처리할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
from multiprocessing import Pool

def square(n):
    return n ** 2

if __name__ == "__main__":
    with Pool(4) as pool:  # 최대 4개의 프로세스
        numbers = [1, 2, 3, 4, 5]
        results = pool.map(square, numbers)
        print(results)  # 출력: [1, 4, 9, 16, 25]

3) 공유 메모리

  • 여러 프로세스 간 데이터를 공유하려면 Value 또는 Array를 사용합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from multiprocessing import Value, Process

def increment(shared_value):
    with shared_value.get_lock():
        shared_value.value += 1

if __name__ == "__main__":
    counter = Value('i', 0)  # 정수형 공유 변수
    processes = [Process(target=increment, args=(counter,)) for _ in range(5)]

    for p in processes:
        p.start()

    for p in processes:
        p.join()

    print(f"최종 값: {counter.value}")  # 출력: 최종 값: 5

3. 비동기 프로그래밍

비동기 프로그래밍(Asynchronous Programming)은 작업이 완료될 때까지 기다리지 않고, 다른 작업을 수행하며 응답을 처리하는 방식입니다.

1) asyncio 기본 사용법

  • asyncawait 키워드를 사용하여 비동기 코드를 작성할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
import asyncio

async def say_hello():
    print("Hello!")
    await asyncio.sleep(1)
    print("Goodbye!")

asyncio.run(say_hello())
# 출력:
# Hello!
# (1초 대기)
# Goodbye!

2) 여러 작업 동시에 실행

  • asyncio.gather를 사용하면 여러 작업을 병렬로 실행할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import asyncio

async def task(name, delay):
    print(f"Task {name} 시작")
    await asyncio.sleep(delay)
    print(f"Task {name} 완료")

async def main():
    await asyncio.gather(
        task("A", 2),
        task("B", 1),
        task("C", 3)
    )

asyncio.run(main())
# 출력:
# Task A 시작
# Task B 시작
# Task C 시작
# Task B 완료
# Task A 완료
# Task C 완료

3) 비동기 파일 처리

  • 비동기 라이브러리 aiofiles를 사용하면 파일 처리도 비동기로 수행할 수 있습니다.
1
2
3
4
5
6
7
8
import aiofiles
import asyncio

async def write_file():
    async with aiofiles.open("example.txt", "w") as f:
        await f.write("비동기 파일 작성!")

asyncio.run(write_file())

4. concurrent.futures 모듈

  • concurrent.futures는 스레드 및 프로세스를 쉽게 관리할 수 있는 고수준 인터페이스를 제공합니다.

1) 스레드 풀 사용

1
2
3
4
5
6
7
8
9
from concurrent.futures import ThreadPoolExecutor

def square(n):
    return n ** 2

with ThreadPoolExecutor() as executor:
    numbers = [1, 2, 3, 4, 5]
    results = list(executor.map(square, numbers))
    print(results)  # 출력: [1, 4, 9, 16, 25]

2) 프로세스 풀 사용

1
2
3
4
5
6
7
8
9
from concurrent.futures import ProcessPoolExecutor

def cube(n):
    return n ** 3

with ProcessPoolExecutor() as executor:
    numbers = [1, 2, 3, 4, 5]
    results = list(executor.map(cube, numbers))
    print(results)  # 출력: [1, 8, 27, 64, 125]

5. 병렬 처리와 비동기 프로그래밍의 차이점

특징병렬 처리비동기 프로그래밍
작업 방식여러 CPU 코어에서 동시에 실행하나의 스레드에서 작업을 비동기로 실행
적용 대상CPU 집약적 작업I/O 집약적 작업
대표 라이브러리multiprocessing, concurrent.futuresasyncio, aiohttp, aiofiles

정리

  • 병렬 처리는 CPU를 최대한 활용해 동시에 여러 작업을 수행하며, multiprocessingconcurrent.futures를 활용합니다.
  • 비동기 프로그래밍은 작업 대기 시간을 활용해 효율적인 실행을 가능하게 하며, asyncio를 사용합니다.
  • 작업의 종류에 따라 병렬 처리와 비동기 프로그래밍을 적절히 선택하면 프로그램의 성능을 극대화할 수 있습니다.

다음 글 예고:
이제 파이썬의 라이브러리를 활용해 데이터 분석과 시각화를 배우는 “Numpy와 Pandas, Matplotlib와 Seaborn”을 다뤄보겠습니다!

This post is licensed under CC BY 4.0 by the author.