20장: 병렬 처리

파이썬은 병렬 처리를 통해 동시에 여러 작업을 수행할 수 있는 다양한 도구를 제공합니다. 이 장에서는 `threading`, `multiprocessing`, 그리고 `concurrent.futures` 모듈을 사용하여 병렬 처리를 구현하는 방법을 알아보겠습니다.


#### 20.1 멀티스레딩 (Threading)


`threading` 모듈을 사용하여 멀티스레딩을 구현할 수 있습니다. 스레드는 프로세스 내에서 실행되는 경량 실행 단위로, 동일한 메모리 공간을 공유합니다.


##### 20.1.1 기본 멀티스레딩 예제


다음은 `threading` 모듈을 사용하여 멀티스레딩을 구현하는 기본 예제입니다.


```python

import threading


def print_numbers():

    for i in range(10):

        print(i)


def print_letters():

    for letter in 'abcdefghij':

        print(letter)


# 스레드 생성

thread1 = threading.Thread(target=print_numbers)

thread2 = threading.Thread(target=print_letters)


# 스레드 시작

thread1.start()

thread2.start()


# 스레드가 종료될 때까지 기다림

thread1.join()

thread2.join()


print("모든 스레드가 종료되었습니다.")

```


##### 20.1.2 스레드 안전 (Thread Safety)


스레드 간의 데이터 접근을 안전하게 하기 위해서는 `Lock` 객체를 사용할 수 있습니다.


```python

import threading


lock = threading.Lock()

shared_resource = 0


def increment():

    global shared_resource

    with lock:

        for _ in range(1000000):

            shared_resource += 1


# 스레드 생성

thread1 = threading.Thread(target=increment)

thread2 = threading.Thread(target=increment)


# 스레드 시작

thread1.start()

thread2.start()


# 스레드가 종료될 때까지 기다림

thread1.join()

thread2.join()


print(f"공유 자원의 값: {shared_resource}")

```


#### 20.2 멀티프로세싱 (Multiprocessing)


`multiprocessing` 모듈을 사용하여 멀티프로세싱을 구현할 수 있습니다. 프로세스는 독립적인 메모리 공간을 가지므로, 병렬 처리를 통해 성능을 높일 수 있습니다.


##### 20.2.1 기본 멀티프로세싱 예제


다음은 `multiprocessing` 모듈을 사용하여 멀티프로세싱을 구현하는 기본 예제입니다.


```python

import multiprocessing


def print_numbers():

    for i in range(10):

        print(i)


def print_letters():

    for letter in 'abcdefghij':

        print(letter)


# 프로세스 생성

process1 = multiprocessing.Process(target=print_numbers)

process2 = multiprocessing.Process(target=print_letters)


# 프로세스 시작

process1.start()

process2.start()


# 프로세스가 종료될 때까지 기다림

process1.join()

process2.join()


print("모든 프로세스가 종료되었습니다.")

```


##### 20.2.2 프로세스 간 통신 (IPC)


`multiprocessing` 모듈의 `Queue` 객체를 사용하여 프로세스 간 통신을 구현할 수 있습니다.


```python

import multiprocessing


def producer(queue):

    for i in range(5):

        queue.put(i)

        print(f"생산자: {i} 생성")


def consumer(queue):

    while not queue.empty():

        item = queue.get()

        print(f"소비자: {item} 소비")


queue = multiprocessing.Queue()


# 프로세스 생성

producer_process = multiprocessing.Process(target=producer, args=(queue,))

consumer_process = multiprocessing.Process(target=consumer, args=(queue,))


# 프로세스 시작

producer_process.start()

producer_process.join()


consumer_process.start()

consumer_process.join()


print("생산자와 소비자 프로세스가 종료되었습니다.")

```


#### 20.3 `concurrent.futures`


`concurrent.futures` 모듈은 고수준의 병렬 처리를 위한 인터페이스를 제공합니다. `ThreadPoolExecutor`와 `ProcessPoolExecutor`를 사용하여 병렬 처리를 쉽게 구현할 수 있습니다.


##### 20.3.1 `ThreadPoolExecutor` 예제


다음은 `ThreadPoolExecutor`를 사용하여 멀티스레딩을 구현하는 예제입니다.


```python

from concurrent.futures import ThreadPoolExecutor


def print_numbers():

    for i in range(10):

        print(i)


def print_letters():

    for letter in 'abcdefghij':

        print(letter)


# 스레드 풀 생성

with ThreadPoolExecutor(max_workers=2) as executor:

    executor.submit(print_numbers)

    executor.submit(print_letters)


print("모든 작업이 완료되었습니다.")

```


##### 20.3.2 `ProcessPoolExecutor` 예제


다음은 `ProcessPoolExecutor`를 사용하여 멀티프로세싱을 구현하는 예제입니다.


```python

from concurrent.futures import ProcessPoolExecutor


def print_numbers():

    for i in range(10):

        print(i)


def print_letters():

    for letter in 'abcdefghij':

        print(letter)


# 프로세스 풀 생성

with ProcessPoolExecutor(max_workers=2) as executor:

    executor.submit(print_numbers)

    executor.submit(print_letters)


print("모든 작업이 완료되었습니다.")

```


#### 20.4 비동기 프로그래밍 (Asynchronous Programming)


`asyncio` 모듈은 비동기 프로그래밍을 지원합니다. 비동기 프로그래밍을 통해 I/O 바운드 작업을 효율적으로 처리할 수 있습니다.


##### 20.4.1 기본 비동기 예제


다음은 `asyncio` 모듈을 사용하여 비동기 프로그래밍을 구현하는 예제입니다.


```python

import asyncio


async def print_numbers():

    for i in range(10):

        print(i)

        await asyncio.sleep(0.1)


async def print_letters():

    for letter in 'abcdefghij':

        print(letter)

        await asyncio.sleep(0.1)


async def main():

    await asyncio.gather(print_numbers(), print_letters())


# 이벤트 루프 실행

asyncio.run(main())

```


##### 20.4.2 비동기 HTTP 요청


`aiohttp` 라이브러리를 사용하여 비동기 HTTP 요청을 보낼 수 있습니다. 먼저 `aiohttp`를 설치해야 합니다.


```sh

pip install aiohttp

```


다음은 `aiohttp`를 사용하여 비동기 HTTP 요청을 보내는 예제입니다.


```python

import aiohttp

import asyncio


async def fetch(url):

    async with aiohttp.ClientSession() as session:

        async with session.get(url) as response:

            return await response.text()


async def main():

    url = 'https://api.github.com'

    html = await fetch(url)

    print(html)


# 이벤트 루프 실행

asyncio.run(main())

```


이상으로, 파이썬에서 병렬 처리와 비동기 프로그래밍을 수행하는 방법에 대해 알아보았습니다. 다음 장에서는 파이썬을 사용한 데이터베이스 작업에 대해 더 자세히 알아보겠습니다. 질문이나 요청사항이 있으시면 댓글로 남겨주세요!


---


이 글의 내용은 GoalKicker.com의 Python Notes for Professionals 책을 참조하였습니다.

댓글