개요
과거 진행한 프로젝트에서 최적화를 진행했는데,
관련 내용을 기록해두지 않은게 생각났다.
프로젝트에서 스크린샷 수집을 위해 셀레니움을 활용했었다.
매 요청 당 최대 1000개씩 발생하기도 하는데,
드라이버 하나로 스크린샷 1000개를 생성하다니 수집률이 너무 떨어졌었다.
이런 이유로 멀티 스레딩을 활용한 병렬 처리가 필수적이었는데,
각 스레드에서 크롬 드라이버를 '열고 캡쳐하고 닫고'를 하자니 오버헤드가 너무 컸다.
이 문제를 전공 지식을 활용해 해결한 것에 대한 내용이다.
파이썬 멀티 스레딩을 사용해보자!
파이썬 multiprocessing.pool 라이브러리의 ThreadPool 이용했다.
사용 이유:
1) Multi Threading 지원
2) Thread 개수 지정 가능 (Chrome Driver는 CPU 리소스를 많이 사용하기 때문에 제한 필요)
3) Thread로 수행된 테스크의 리턴값을 가져올 수 있음 (내장 Threading라이브러리는 지원하지 않음)
ThreadPool 은 다음과 같이 이용하면 된다.
test_pool = ThreadPool(processes=3)
test_result = test_pool.apply_async(test_method, (파라미터1, 파라미터2)) # 파라미터는 튜플로 묶어 전달
fs_file_id, hs_file_id = test_result.get()
아이디어 흐름
드라이버를 열고 닫는 오버헤드가 크다.
-> 드라이버를 재활용하면 된다.
멀티 스레딩을 이용해서 여러 스크린샷 요청이 생성된다.
-> 스레드 풀에서 설정한 개수만큼 드라이버를 생성한다.
여러 개의 드라이버를 공유 자원으로 활용해야한다.
-> 큐에 드라이버를 저장해두고, 필요할 때 꺼내 쓰고 반납하는 방식을 활용했다.
스레드들이 드라이버를 할당 받기 위해 큐에 접근할 시 레이스 컨디션이 발생할 수 있다.
-> 할당과 반납 시에 뮤택스를 적용하여 레이스 컨디션을 방지했다.
결과
예시 코드
- 크롬 드라이버 큐 생성
self.pool = queue.Queue()
for _ in range(5):
driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()), options=self.chrome_options)
self.pool.put(driver)
- 뮤텍스 적용 (Threading 모듈 활용)
def get_driver(self): # 할당 받기
with self.lock:
return self.pool.get()
def release_driver(self, driver): # 반납하기
with self.lock:
self.pool.put(driver)
로직 시각화
아웃풋 결과
기존 분당 약 8개를 수집하던 아웃풋에서
분당 약 20개까지 아웃풋을 150% 향상시키는 결과를 얻을 수 있었다.
이게 맞는 로직인지는 모르겠지만,
어떻게 보면 OS 강의 때 흥미롭게 배운 내용을 처음 제대로 활용해 본 경험이였다.
'개발 메모' 카테고리의 다른 글
Github Submodule 연결하기 (0) | 2024.10.18 |
---|---|
ELK stack + Kafka 적용 일지 (0) | 2024.08.12 |