요즘IT
위시켓
최근 검색어
전체 삭제
최근 검색어가 없습니다.

본문은 요즘IT와 번역가 David가 함께 아서 파스텔(Arthur Pastel)의 글 <State of Python 3.13 Performance: Free-Threading>을 번역한 글입니다. 필자는 파리에서 활동하는 Python 개발자이자, 오픈소스 애호가로 MongoDB를 위한 ODMantic을 개발했습니다. 현재는 CI 파이프라인에서 성능 문제를 예방하는 솔루션 ‘CodSpeed’의 창업자로 활동하고 있습니다. 이 글에서는 파이썬 3.13에서의 주요 성능 변화와 ‘Free-threading’ 기능을 소개합니다.

회원가입을 하면 원하는 문장을
저장할 수 있어요!

다음

회원가입을 하면
성장에 도움이 되는 콘텐츠를
스크랩할 수 있어요!

확인

개발

파이썬 3.13 성능 향상 완전 정복: Free-Threading

년차,
어떤 스킬
,
어떤 직무
독자들이 봤을까요?
어떤 독자들이 봤는지 궁금하다면?
로그인

본문은 요즘IT와 번역가 David가 함께 아서 파스텔(Arthur Pastel)의 글 <State of Python 3.13 Performance: Free-Threading>을 번역한 글입니다. 필자는 파리에서 활동하는 Python 개발자이자, 오픈소스 애호가로 MongoDB를 위한 ODMantic을 개발했습니다. 현재는 CI 파이프라인에서 성능 문제를 예방하는 솔루션 ‘CodSpeed’의 창업자로 활동하고 있습니다. 이 글에서는 파이썬 3.13에서의 주요 성능 변화와 ‘Free-threading’ 기능을 소개합니다.

 

필자에게 허락을 받고 번역했으며, 글에 포함된 각주(*표시)는 ‘번역자주’입니다.

 

지난 10월에 출시된 파이썬 3.13은 최근 릴리스 중에서도 성능 향상에 가장 큰 중점을 둔 버전입니다. 릴리스 노트를 살펴보면 성능에 큰 영향을 미칠 수 있는 주요 변경 사항들이 눈에 띕니다.

 

  • 파이썬이 이제 전역 인터프리터 잠금(GIL*)을 비활성화한 free-threaded 모드로 실행 가능합니다.
  • 완전히 새로운 just-in-time(JIT*) 컴파일러가 추가되었습니다.
  • 파이썬이 이제 기본적으로 mimalloc* 할당자를 포함하고 있습니다.

 

*GIL: 한 번에 하나의 스레드만 파이썬 코드를 실행할 수 있도록 하는 잠금 장치

*JIT: 프로그램 실행 중에 자주 사용되는 코드를 실시간으로 기계어로 번역해 성능을 향상시키는 컴파일 기술

*mimalloc: Microsoft가 개발한 고성능 메모리 할당자로, 일반 malloc보다 더 빠르고 메모리 단편화가 적은 최신 메모리 관리 라이브러리

*malloc: 프로그램 실행 중에 필요한 메모리를 동적으로 할당받는 C 언어의 기본 메모리 할당 함수

 

이 글에서는 free-threaded 모드를 중점적으로 살펴보고, 이러한 변화가 파이썬 애플리케이션의 성능에 미치는 영향을 측정해 볼 예정입니다.

 

 

Free-threaded 파이썬 소개

Free-threading은 파이썬 3.13에서 도입된 실험적 기능으로, 파이썬이 전역 인터프리터 잠금(GIL) 없이 실행될 수 있도록 하는 기능입니다. GIL은 여러 스레드가 동시에 파이썬 바이트코드를 실행하는 것을 막는 상호 배제(mutex) 장치입니다. 이러한 설계는 파이썬의 메모리 관리를 단순화하고, C API 사용을 쉽게 만들어주었지만, 현대의 멀티코어 프로세서를 효과적으로 활용하는 데 있어 가장 큰 장애물 중 하나로 작용해 왔습니다.

 

기존의 멀티프로세싱 우회 방안

전통적으로는 multiprocessing 모듈을 사용하여 이 문제를 해결해 왔습니다. 이 모듈은 스레드 대신 별도의 파이썬 프로세스를 생성하는 방식을 사용합니다. 이러한 접근 방식이 동작은 하지만, 다음과 같은 중요한 제약 사항들이 있습니다.

 

  1. 메모리 오버헤드: 각 프로세스는 자체 파이썬 인터프리터 인스턴스와 메모리 공간을 필요로 합니다. 데이터를 많이 다루는 애플리케이션의 경우 이는 빠르게 병목 현상으로 이어질 수 있습니다.
  2. 통신 비용: 프로세스들은 메모리를 직접 공유할 수 없습니다. 프로세스 간에 데이터를 주고받을 때마다 직렬화와 역직렬화 과정이 필요하며, 이는 추가적인 오버헤드와 복잡성을 야기합니다.
  3. 시작 시각: 새로운 프로세스를 생성하는 것은 스레드를 생성하는 것보다 현저히 느립니다. 따라서 작업자(worker)를 자주 생성해야 하는 작업에는 실용적이지 않습니다.

 

 

실제 활용 사례: PageRank 구현

이러한 제약 사항을 실제로 확인하기 위해 PageRank 알고리즘의 구현 사례를 살펴보겠습니다. PageRank는 초기 구글의 검색 엔진을 지원했던 알고리즘으로, 다음과 같은 특성으로 인해 이상적인 예시가 됩니다.

 

  1. 계산 집약적인 작업(행렬 연산)을 수행합니다.
  2. 대규모 데이터셋(웹 그래프)을 처리합니다.
  3. 병렬화를 통해 상당한 성능 개선을 기대할 수 있습니다.

 

파이썬 3.12 이전 버전에서 단순한 멀티스레드 구현을 시도할 경우, 행렬 연산 과정에서 GIL로 인한 병목 현상이 발생하게 됩니다. 한편 멀티프로세싱 방식을 사용할 경우에는 다음과 같은 문제에 직면하게 됩니다.

 

  • 각 프로세스에 그래프를 복사하는 데 따른 메모리 오버헤드
  • 프로세스 간 부분 결과를 전송하는 데 드는 비용
  • 공유 상태 관리의 복잡성

 

다음으로 다양한 동시성 모델을 통한 구현 방법을 살펴보도록 하겠습니다.

 

 

다양한 동시성 모델을 통한 구현

기본 구현 (단일 스레드)

 

이 알고리즘에서 계산 비용이 가장 많이 드는 부분은 색칠된 두 곳입니다. 첫 번째는 진입 노드들로부터의 점수 기여분을 계산하는 부분이고, 두 번째는 댐핑 팩터를 적용하여 새로운 점수를 최종 결과에 반영하는 부분입니다. 이 중에서 첫 번째 부분을 병렬화하는 것이 가장 효과적이면서도 구현하기 쉬운 방법이 될 것입니다. 범위를 분할하여 여러 스레드가 new_scores 배열을 효율적으로 계산할 수 있기 때문입니다.

 

멀티스레드 구현

멀티스레드 구현에서는 먼저 행렬을 여러 개의 청크*로 나누는 것부터 시작합니다.

*청크: 큰 데이터를 작은 조각으로 나눠서 하나씩 처리하는 방식

 

 

그런 다음 각 스레드는 행렬의 서로 다른 청크에 대해 작업을 수행하며, 새로운 점수를 갱신합니다.

 

 

여기서 주목할 점은 new_scores 배열의 갱신이 잠금 된 상태에서 이루어진다는 것입니다. 이는 경쟁 상태를 방지하기 위한 것입니다. 잠금 상태가 오래 유지되면 병목 현상이 될 수 있지만, 실제로는 알고리즘의 첫 번째 부분을 병렬화하는 것만으로도 상당한 성능 향상을 얻을 수 있습니다.

 

마지막으로 각 스레드에 청크를 할당하여 처리합니다.

 

 

멀티프로세스 구현

멀티프로세스 구현은 기본적으로 멀티스레드 구현과 매우 유사합니다. 주요 차이점들을 살펴보겠습니다.

  • 프로세스들은 메모리를 직접 공유할 수 없기 때문에, 각 워커는 공유 new_scores 배열을 갱신하는 대신 local_scores 배열을 반환합니다. 그 후 메인 프로세스에서 로컬 점수들을 취합합니다.

 

 

이 방식은 멀티스레드 버전보다 빠를 수 있지만, 프로세스 간 통신에 따른 오버헤드가 발생합니다. 특히 대규모 데이터셋의 경우 이 오버헤드가 상당히 커질 수 있습니다.

  • ThreadPoolExecutor 대신 multiprocessing.Pool을 사용합니다. API는 매우 비슷하지만, multiprocessing.Pool은 스레드 대신 프로세스 풀을 생성합니다.

 

 

 

성능 측정

실제 성능 변화를 측정하기 위해 성능 테스트를 구축해 보겠습니다. 우선 테스트용 데이터를 생성하는 것부터 시작합니다.

 

테스트 데이터 생성

 

여기서는 실행마다 동일한 결과를 보장하기 위해 고정된 시드값을 사용합니다. 이는 서로 다른 구현 방식의 성능을 비교할 때 매우 중요합니다. 페이지 간의 가짜 연결을 생성하여 현실적인 그래프를 만들고 있지만, 행렬의 크기가 동일하다면 빈 행렬을 사용하더라도 수학적 연산은 정확히 동일할 것입니다.

 

벤치마크 케이스 정의

다음으로, pytest-codspeed라는 pytest 플러그인을 사용하여 다양한 매개변수와 여러 파이썬 버전/빌드에 대한 성능을 측정해 보겠습니다.

 

 

여기서는 3가지 구현 방식을 3가지 다른 그래프 크기로 테스트합니다. pytest-codspeed가 제공하는 benchmark를 사용하여, 주어진 인자로 pagerank 함수의 실행 시간을 측정합니다.

 

 

깃허브 액션 워크플로우 설정

CodSpeed의 인프라에서 다양한 파이썬 빌드의 성능을 측정하기 위한 깃허브 액션 워크플로우를 작성합니다.

 

 

이 설정에서는 파이썬 3.12, 3.13, 그리고 free threading 지원이 포함된 3.13에 대해 GIL을 활성화한 경우와 비활성화한 경우 모두에서 벤치마크를 실행합니다. 이를 통해 GIL이 활성화된 상태에서도 free-threading의 영향을 확인할 수 있습니다.

 

 

성능 측정 결과는?

 

분석 결과

  • 새로운 빌드 옵션을 활성화하지 않은 상태에서는 3.123.13 버전이 매우 유사한 성능을 보여주었습니다. 또한 multiprocessing 구현의 한계도 명확히 드러났는데, 프로세스 간 통신 오버헤드로 인해 오히려 단일 스레드 구현보다 더 느린 결과를 보여주었습니다.
  • 예상대로 GIL이 비활성화된 3.13에서 threading 기반 구현이 가장 빠른 성능을 보여주었습니다. GIL이 더 이상 스레드의 병렬 실행을 제한하지 않게 되었기 때문입니다.
  • 그러나 free-threaded 빌드에서는 GIL의 활성화 여부와 관계없이 다른 모든 구현에서 상당한 성능 저하가 관찰되었습니다. 이는 주로 free-threaded 빌드에서 specializing adaptive interpreter(SAI*)를 비활성화해야 하기 때문입니다. 이로 인해 다른 구현들의 성능이 눈에 띄게 감소했습니다. 이러한 오버헤드는 3.14 릴리스에서 개선될 예정입니다. 해당 버전에서는 specializing adaptive interpreter가 스레드 안전성을 확보하여 재활성화될 것이기 때문입니다. 그 시점에서는 많은 병렬 애플리케이션에서 free-threaded 빌드로의 전환이 자연스러운 선택이 될 것이며, 성능 변화를 측정하는 것도 흥미로울 것입니다.

*SAI: 프로그램 실행 중에 코드를 분석하고 최적화하는 특별한 종류의 인터프리터

 

다른 모든 그래프 크기에서도 결과는 매우 유사했으며, 동일한 결론에 도달했습니다. 이번 측정을 통해 파이썬 3.13의 새로운 free-threaded 빌드가 병렬 애플리케이션의 성능에 상당한 영향을 미칠 수 있으며, multiprocessing의 매우 유의미한 대안이 될 수 있음을 확인했습니다. 다만 아직은 실험적인 기능이며, 전반적인 성능 저하로 인해 프로덕션 환경에서 사용하기에는 이른 단계이지만, 올바른 방향으로 나아가는 매우 유망한 진전이라고 할 수 있습니다.

 

참고 사항

이번 벤치마크에는 Python 3.12에서 도입된 GIL 없이 Python 코드를 병렬로 실행하는 또 다른 방식인 subinterpreters*는 포함되지 않았습니다. Subinterpreters는 대부분의 경우에서 다른 접근 방식들보다 느린 것으로 확인되었는데, 이는 주로 데이터 공유와 워커 간 통신 문제가 아직 완전히 해결되지 않았기 때문입니다. 하지만 이러한 문제들이 해결된다면, multiprocessing의 훌륭한 대안이 될 수 있을 것입니다.

*subinterpreters: 하나의 프로세스 안에서 여러 개의 완전히 독립된 파이썬 인터프리터를 실행해 GIL 없이 진정한 병렬 처리를 가능하게 하는 파이썬 3.12의 기능 중 하나.


<원문>

State of Python 3.13 Performance: Free-Threading

 

위 번역글의 원 저작권은 Arthur Pastel에게 있으며, 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다

좋아요

댓글

공유

공유

댓글 0
작가
469
명 알림 받는 중

작가 홈

작가
469
명 알림 받는 중
요즘 해외 개발자들은 어떻게 일할까요? 기획자나 디자이너는요? 그래서 준비했습니다. 읽어볼만한 해외 소식들을 번역해 전합니다. "We are the world."

좋아요

댓글

스크랩

공유

공유

요즘IT가 PICK한 뉴스레터를 매주 목요일에 만나보세요

요즘IT가 PICK한 뉴스레터를
매주 목요일에 만나보세요

뉴스레터를 구독하려면 동의가 필요합니다.
https://auth.wishket.com/login