Python 멀티프로세싱으로 크롤러 성능 개선

문제 상황

5만 개 상품 데이터를 수집하는 크롤러가 12시간 이상 소요되고 있었다. Threading으로 개선을 시도했지만 GIL 때문에 CPU 코어를 제대로 활용하지 못했다.

multiprocessing 적용

concurrent.futures.ProcessPoolExecutor를 사용해 프로세스 풀을 구성했다.

from concurrent.futures import ProcessPoolExecutor, as_completed
import requests
from bs4 import BeautifulSoup

def crawl_product(url):
    response = requests.get(url, timeout=10)
    soup = BeautifulSoup(response.content, 'html.parser')
    return {
        'url': url,
        'title': soup.select_one('.product-title').text,
        'price': soup.select_one('.price').text
    }

if __name__ == '__main__':
    urls = load_urls()  # 5만개 URL
    results = []
    
    with ProcessPoolExecutor(max_workers=8) as executor:
        futures = {executor.submit(crawl_product, url): url for url in urls}
        
        for future in as_completed(futures):
            try:
                result = future.result(timeout=30)
                results.append(result)
            except Exception as e:
                print(f"Error: {e}")

주의사항

프로세스 생성 오버헤드가 있어서 작업 단위가 너무 작으면 오히려 느려진다. 배치 단위를 500개씩 묶어서 처리했더니 더 효율적이었다.

if __name__ == '__main__' 가드를 반드시 추가해야 Windows 환경에서 무한 프로세스 생성을 막을 수 있다.

결과

12시간 → 2시간으로 단축되었다. CPU 사용률도 15%에서 85%로 올라갔다. 다만 메모리 사용량이 4배 증가해서 프로세스 수를 조정할 필요가 있었다.