Python - 12. 동시성과 병렬 처리
2025. 1. 20. 00:15ㆍ프로그래밍 언어/Python
Python에서는 동시성(Concurrency)과 병렬성(Parallelism)을 구현하기 위한 다양한 도구와 라이브러리를 제공합니다. 이 섹션에서는 멀티스레딩, 멀티프로세싱, 비동기 프로그래밍의 기초 및 고급 활용법을 살펴봅니다.
12.1 멀티스레딩
멀티스레딩이란?
멀티스레딩은 하나의 프로세스 내에서 여러 스레드가 작업을 수행하도록 합니다. 주로 I/O 바운드 작업에 적합합니다.
스레드 동기화
여러 스레드가 동일한 자원을 공유할 때, 동기화 기법을 사용하여 데이터 충돌을 방지해야 합니다.
import threading
import time
balance = 0
lock = threading.Lock()
def deposit(amount):
global balance
with lock: # Lock을 사용하여 동기화
local_balance = balance
time.sleep(0.1)
local_balance += amount
balance = local_balance
threads = []
for _ in range(5):
t = threading.Thread(target=deposit, args=(100,))
threads.append(t)
t.start()
for t in threads:
t.join()
print(f"Final balance: {balance}")
스레드 풀 사용
ThreadPoolExecutor를 사용하여 스레드를 효율적으로 관리할 수 있습니다.
from concurrent.futures import ThreadPoolExecutor
def task(n):
print(f"Task {n} 시작")
time.sleep(1)
print(f"Task {n} 완료")
with ThreadPoolExecutor(max_workers=3) as executor:
for i in range(5):
executor.submit(task, i)
12.2 멀티프로세싱
멀티프로세싱이란?
멀티프로세싱은 여러 프로세스를 활용하여 병렬 처리를 수행합니다. 주로 CPU 바운드 작업에 적합합니다.
프로세스 간 데이터 공유
Value와 Array를 사용하여 데이터를 공유할 수 있습니다.
from multiprocessing import Process, Value, Array
shared_value = Value('i', 0)
shared_array = Array('i', [0, 0, 0])
def modify_data():
shared_value.value += 1
for i in range(len(shared_array)):
shared_array[i] += 1
processes = [Process(target=modify_data) for _ in range(3)]
for p in processes:
p.start()
for p in processes:
p.join()
print(shared_value.value) # 3
print(shared_array[:]) # [3, 3, 3]
Pool 사용
Pool은 작업을 병렬로 실행할 때 유용합니다.
from multiprocessing import Pool
def square(n):
return n * n
with Pool(4) as pool:
results = pool.map(square, [1, 2, 3, 4])
print(results) # [1, 4, 9, 16]
12.3 비동기 프로그래밍 기초
비동기 프로그래밍이란?
비동기 프로그래밍은 작업이 완료될 때까지 기다리지 않고, 다른 작업을 수행할 수 있도록 합니다. 주로 I/O 바운드 작업에 적합합니다.
에러 처리 예제
import asyncio
async def task_with_error():
try:
raise ValueError("Error in task")
except ValueError as e:
print(f"Handled error: {e}")
asyncio.run(task_with_error())
타임아웃 처리
import asyncio
async def long_running_task():
await asyncio.sleep(10)
return "Task Completed"
async def main():
try:
result = await asyncio.wait_for(long_running_task(), timeout=5)
print(result)
except asyncio.TimeoutError:
print("Task timed out")
asyncio.run(main())
동시성 제한
Semaphore를 사용하여 동시에 실행되는 작업의 개수를 제한할 수 있습니다.
import asyncio
semaphore = asyncio.Semaphore(2)
async def limited_task(name):
async with semaphore:
print(f"Task {name} 시작")
await asyncio.sleep(2)
print(f"Task {name} 완료")
async def main():
tasks = [limited_task(i) for i in range(5)]
await asyncio.gather(*tasks)
asyncio.run(main())
12.4 asyncio와 async/await
asyncio 주요 기능
- 코루틴 실행
- 태스크(Task) 생성 및 관리
- 비동기 I/O 처리
태스크 예제
import asyncio
async def task1():
await asyncio.sleep(2)
print("Task 1 완료")
async def task2():
await asyncio.sleep(1)
print("Task 2 완료")
async def main():
await asyncio.gather(task1(), task2())
asyncio.run(main())
12.5 비동기 웹 크롤링
aiohttp를 활용한 웹 크롤링
import asyncio
import aiohttp
async def fetch_url(session, url):
async with session.get(url) as response:
return await response.text()
async def main():
urls = ["https://example.com" for _ in range(5)]
async with aiohttp.ClientSession() as session:
tasks = [fetch_url(session, url) for url in urls]
responses = await asyncio.gather(*tasks)
for response in responses:
print(response[:100]) # 응답 내용 일부 출력
asyncio.run(main())
12.6 비동기 데이터베이스 처리
asyncpg를 활용한 비동기 데이터베이스 처리
import asyncio
import asyncpg
async def fetch_data():
conn = await asyncpg.connect(user="user", password="password", database="testdb", host="127.0.0.1")
rows = await conn.fetch("SELECT * FROM my_table")
for row in rows:
print(row)
await conn.close()
asyncio.run(fetch_data())
이번 섹션에서는 Python에서 동시성과 병렬 처리를 구현하는 다양한 방법과 활용 사례를 살펴보았습니다. 적절한 도구를 선택하여 프로그램의 성능과 효율성을 극대화할 수 있습니다.
'프로그래밍 언어 > Python' 카테고리의 다른 글
Python - 13. 코드 품질과 테스팅 (0) | 2025.01.20 |
---|---|
Python Tkinter - 2. 레이아웃 관리와 고급 이벤트 처리 (0) | 2025.01.20 |
Python Tkinter - 1. 소개와 기본 위젯 (0) | 2025.01.20 |
Python - 11. 내장 함수와 표준 라이브러리 (0) | 2025.01.19 |
Python - 10. 모듈과 패키지 (0) | 2025.01.19 |