logo
logo
언어
Python
StackOverflow 질문 수: 2201103
사용 기업
교육
인공지능
기타
직장
소셜/컨텐츠
금융/보험
패션
부동산/인테리어
이커머스
모빌리티
여행
푸드테크
헬스케어
종합
블록체인
techstack-logo
클라썸
techstack-logo
슈퍼브에이아이
techstack-logo
엔라이튼
techstack-logo
토스랩
techstack-logo
큐피스트
techstack-logo
핀다
techstack-logo
드라마앤컴퍼니
techstack-logo
딜리셔스
techstack-logo
파운트
techstack-logo
뤼이드
techstack-logo
직방
techstack-logo
에이블리
techstack-logo
플렉스
techstack-logo
식스샵
techstack-logo
드림어스컴퍼니
techstack-logo
숨고
techstack-logo
스푼
techstack-logo
바로고
더 보기
기술 블로그 글
SK텔레콤
Cache를 통해 파이썬 성능을 향상시켜보자!
파이썬을 어느 정도 사용하시고 계시다면, 성능에 대해 고민을 많이 해보실 텐데요.여러 번 함수를 실행해야 하고 일부 결과를 재 사용해야 하는 상황을 겪어본 적이 있으신가요?파이썬 내장 함수인 functools 내 cache, lru_cache 데코레이터를 소개하겠습니다.알고리즘 및 자료구조 기초인 피보나치 재귀 함수를 통해 얼마나 성능 항샹이 되는지 비교해볼 수 있습니다.대부분의 다른 프로그래밍 언어와 마찬가지로, 파이썬도 재귀 함수에 대한 "스택"을 구축하고 모든 스택에서 값을 계산해야 합니다.하지만 우리는 functools 의 "cache" decorator를 통해 성능을 상당히 향상시킬 수 있습니다.다음은 실행 결과와 성능 비교입니다.316 ms는 15.9 µs의 약 20000 배로 성능이 향상된 것을 알 수 있는데요.약간 과장같아 보이지만? 실제로 Cache를 사용하면 이렇게 최적화할 수 있다는 것을 보여줍니다.몇가지 한계가 있습니다. 이는 메모리 관련 문제인데요. 아래 예시를 한 번 들어보겠습니다.• None DB에서 사용자 세부 정보를 가져오는 API Endpoint를 개발 중• None 간단하기 위해 여러 비즈니스 로직은 생략하고 사용자를 무작위로 반환하는 함수만 정의위 코드에서는 random 모듈을 사용하여 이 사용자의 나이와 자기 소개를 생성했습니다.자기 소개는 시뮬레이션을 위해 무작위 문자로 이루어진 길이 1000의 string 문자열입니다.이제 이 Endpoint를 호출한다고 가정하고, get_user_data() 함수 호출 시뮬레이션 함수를 작성해 보겠습니다.메모리 사용량을 이해하기 위해 파이썬에 내장된 tracemalloc 모듈을 사용해야 합니다.결과는 아래와 같습니다.시뮬레이션과 메모리 사용량은 1:1 비율로 증가한다는 것을 알 수 있습니다.더 중요한 점은 캐싱에 사용되는 메모리는 Process가 중지될 때까지 사라지지 않습니다.실제 서비스에 사용할 경우, 캐싱이 얼마나 많은 메모리가 필요한지? 추측이 불가능할 수 있습니다.-> 이는 서비스 장애로 나타날 수 있습니다...lru_cache decorator의 "lru" 용어는 "Least Recently Used"의 약어입니다.이는 캐싱 메커니즘에서 사용하는 알고리즘으로, 자주 사용된 데이터를 보유하고 가장 최근에 사용되지 않은 데이터를 삭제하여 메모리를 관리합니다.이는 캐시할 수 있는 데이터의 상한선을 추가할 수 있다는 것을 의미하는 것인데요.이것이 바로 cache와 다르게 lru_cache가 제공하는 유연성입니다.위 @cache와 같이 동일하게 함수를 작성하여 시뮬레이션 해봅시다.아래와 같은 결과를 보실 수 있습니다.@lru_cache(maxsize=1000) 의 maxsize를 통해 첫 1000회 실행에서는 메모리 사용량이 계속 증가하는 것이 보입니다.이후 1001~10000회 실행에 대해선 메모리 사용량이 상당한 증가 없이 안정화되는 것을 볼 수 있습니다.성능을 모니터링하기 위해 cache_info() 함수를 사용할 수 있습니다.이 함수는 현재 캐시의 크기, 캐시된 데이터가 얼마나 자주 사용되었는지(히트 수), 그리고 사용되지 않은 데이터가 얼마나 있는지(미스 수)를 보여줍니다.피보나치 함수를 다시 사용해 보겠습니다.maxsize는 lru_cache의 최대 제한이 최대 32개 객체로 설정되었음을 나타냅니다.• None 이 31개의 캐시된 값 중 28개는 히트• None 또한 31번의 미스가 있었는데, 이는 캐시된 값이 없어 함수가 값을 계산하기 위해 로직을 실행해야 했던 횟수를 의미-> 이 함수에서 우리의 캐싱 전략은 꽤 성공적으로 작동하는 것으로 보입니다.cache_info() 함수는 캐싱 기능이 도움이 되었는지 확인할 수 있는 기준을 제공합니다.예를 들어, 히트가 매우 적고 미스가 많다면, 해당 함수는 캐시할 가치가 없을 수도 있습니다.cache_clear() 함수는 이름에서 쉽게 유추할 수 있습니다. 네, 이 함수를 실행하면 캐시된 모든 결과가 지워집니다.아래와 같이 캐시가 다 지워진 것을 볼 수 있습니다.위에 언급된 두 함수를 통해 캐시를 더 쉽게 관리할 수 있습니다.예를 들어, 캐싱의 큰 문제 중 하나는 메모리가 해제되지 않는다는 점인데,주기적이거나 동적으로 캐시를 지우면 이 문제를 완화하거나 해결할 수 있을 것입니다.파이썬 내장 모듈인 functools의 cache, lru_cache 데코레이터를 소개했습니다.특히 lru_cache는 더 복잡한 상황에서 메모리 누수가 발생하지 않도록 유연성을 제공합니다.이러한 관리 기능을 잘 활용하면 여러분의 서비스에 버그를 피하고 메모리를 효율적으로 활용할 수 있습니다!!
python
SK텔레콤
Streamlit을 활용한 Python 웹 애플리케이션 개발 소개
Fine-tuning 관련 교육을 듣던 중 streamlit을 처음 접하게 되었는데요.손쉽게 웹 애플리케이션을 만들 수 있는 걸 보고 한번쯤 기본 기능들을 둘러보면 좋겠다는 생각에 자료를 조사하며 블로그를 작성하게 되었습니다.Streamlit은 Python에서 사용할 수 있는 오픈소스 웹 애플리케이션 프레임워크입니다.사용자가 Python 스크립트를 사용하여 데이터 시각화, 모델 훈련 결과의 시각화, 인터랙티브한 웹 애플리케이션 등을 손쉽게 개발할 수 있도록 도와줍니다.Streamlit은 사용하기 쉽고 빠르게 웹 애플리케이션을 구축할 수 있는 간단한 컴포넌트 API와 함께 제공되며,사용자가 코드를 수정할 때 자동으로 리로드되어 실시간으로 변경 사항을 확인할 수 있는 장점을 갖고 있습니다.라고 streamlit은 주장하는데요.그럼 바로 띄워보며 살펴보겠습니다.streamlit을 이용하기 위해 필요한 패키지는 streamlit 입니다. streamlit 패키지를 설치하고 바로 실험해볼 수 있는 hello 명령을 제공하고 있습니다.streamlit helllo를 실행하면 아래와 같은 다양한 streamlit으로 구현된 컴포넌트들을 확인 할 수 있습니다.기본 제공하는 컴포넌트들의 퀄리티가 상당히 그럴듯한(?) 것을 확인할 수 있습니다.각각을 띄우기 위해 코드를 많이 작성할 필요도 없습니다. Python 코드 몇줄이면 컴포넌트들이 뚝딱 생성되네요.원격지 소스코드를 Streamlit으로 띄우기streamlit은 Python 스크립트를 로드하여 바로 웹 애플리케이션을 띄우므로 웹 상에 업로드된 Python 모듈을 바로 실행할 수 있습니다.아래와 같이 streamlit run 입력으로 로컬에서 바로 웹 애플리케이션을 동작할 수 있습니다.streamlit에는 사용자와 상호작용하기 위한 다양한 컴포넌트들이 존재합니다.Button, Columns, Tabs, Form, Selectbox 등 다양한 형태의 컴포넌트들을 사용할 수 있습니다.각 컴포넌트들은 속성값을 조절하고 핸들러를 붙여 사용하는 것이 가능합니다.상세한 내용은 가이드 문서의 API reference(https://docs.streamlit.io/develop/api-reference)에서 확인하실 수 있습니다.streamlit을 이용해 네비게이션 가능한 multipage를 구현할 수 있습니다.페이지를 생성하는 방법 역시 간단합니다.메인 스크립트가 위치한 디렉토리에 pages라는 디렉토리를 생성하여 하위에 Python 모듈 파일을 만들면 파일 이름으로 페이지가 생성됩니다.tree 형태로 보면 다음과 같습니다.주의할 점은 sidebar에 있는 메뉴나 st.page_link와 같은 접근 방식이 아닌 URL로 직접 페이지를 접근하는 경우 session 정보가 초기화 된다는 것입니다.Streamlit은 사용자 상호작용이나 코드 변경 시 마다 매번 스크립트의 시작부터 끝까지 재실행합니다. 이러한 방식은 개발은 간단 하지만 두 가지 이슈가 발생합니다.• None 오래 실행되는 함수는 반복해서 실행되므로 앱 속도가 느려집니다.• None 개체가 계속해서 다시 생성되므로 재실행이나 세션에서 개체를 유지하기가 어렵습니다.내장된 캐싱 메커니즘으로 두 가지 문제를 해결할 수 있습니다. 캐싱을 이용하면 느린 함수 호출의 결과를 저장하므로 한 번만 실행하면 됩니다.따라서 앱 속도가 훨씬 빨라지고 재실행 시에도 오브젝트를 유지하는데 도움이 됩니다.캐싱 타입에는 st.cache_data 또는 st.cache_resource 두가지가 존재합니다.st.cache_data는 데이터를 반환하는 계산을 캐시하는 데 권장되는 방법으로,CSV에서 데이터 프레임 로드, NumPy 배열 변환, API 쿼리 또는 직렬화 가능한 데이터 객체(str, int, float, DataFrame, array, list, ...)를 반환하는 기타 함수 등을 캐시합니다.각 함수 호출 시 데이터의 새 복사본을 생성하여 mutation과 race condition으로부터 안전하다고 합니다.st.cache_resource는 여러 번 로드하지 않으려는 직렬화할 수 없는 객체인 ML 모델이나 데이터베이스 연결과 같은 글로벌 리소스를 캐시하는 데 권장되는 방법입니다.이를 사용하면 복사나 복제 없이 앱의 모든 재실행 및 세션에서 이러한 리소스를 공유할 수 있습니다.캐시된 반환값을 변경하면 캐시에 있는 객체가 직접 변경된다는 점에 유의해야 합니다.그렇다면 캐시 사용 시 얼마나 성능 차이가 있을까?본 포스트에서는 st.cache_data만 사용해서 간단히 실행 시간을 비교 해보도록 하겠습니다.테스트 코드는 다음과 같습니다.웹에서 csv 데이터를 불러와 st.dataframe으로 표현하는 코드입니다. 위 코드를 실행하면 다음과 같은 화면이 나옵니다.실행 환경 마다 차이는 있겠지만 제가 측정했을 때의 시간은 다음과 같은 결과가 나왔습니다.사용자와 상호작용하는 인터페이스를 만들기에는 상당한 지연 시간이네요.이런 데이터 로딩 시간을 버튼 클릭 시 마다 격게 되면 사용자 경험을 해치는 결과를 초례합니다.그럼 캐싱을 적용한 경우 얼마나 빨라지는지 보겠습니다.캐싱은 다음과 같이 데코레이터를 추가하는 방법으로 간단히 적용할 수 있습니다.캐시가 적용된 경우 다음과 같은 실행 시간이 나왔습니다.최초 로딩은 느리겠지만 사용자와 상호작용하면서 스크립트가 재실행 되는 경우엔 빠른 반응 속도로 실행될 수 있습니다.사용자가 streamlit앱과 인터랙션할 때마다 streamlit은 스크립트를 시작부터 끝까지 재실행합니다.각 재실행은 백지 상태에서 이루어지며, 실행 간에 변수가 공유되지 않습니다.session_state는 각 사용자 세션에 대해 재실행 간에 변수를 공유하는 방법입니다.streamlit은 상태를 저장하고 유지하는 기능 외에도 콜백을 사용하여 상태를 조작할 수 있는 기능도 제공합니다.세션 상태는 다중 페이지 앱 내의 여러 페이지에서도 유지됩니다.간단한 예제로 보도록 하겠습니다. 흔히 웹프론트엔드에서 사용하는 예제 방식인 버튼 클릭시 숫자를 증가 시키는 예제입니다.아래와 같은 코드를 작성했을 때 버튼 클릭시 count값
github
python
SK텔레콤
AI를 활용한 손쉬운 음성 테스트 데이터 생성
Python에서 음성 파일을 만들고 작성하는 것은 재미있고 유용한 기술이 될 수 있습니다.특히 오디오 피드백이 필요한 앱을 구축하거나 프로젝트의 접근성을 높이는 데 더욱 그렇습니다.이를 달성하는 가장 쉬운 방법 중 하나는 gTTS(Google Text-to-Speech) 라이브러리를 사용하는 것입니다.수행 방법에 대한 초보자 친화적인 가이드는 다음과 같습니다.파이썬이 설치되어 있다는 가정하에, 먼저 gTTS 라이브러리를 설치해야 합니다. 터미널이나 명령 프롬프트를 열고 다음 명령을 입력하십시오.이제 텍스트를 음성으로 변환하고 MP3 파일로 저장하는 간단한 스크립트를 작성해 보겠습니다.함수를 이용하려면 아래와 같이 작성합니다.• None gTTS 가져오기: gtts 모듈에서 gTTS 클래스를 가져오는 것부터 시작합니다. 을 넣지 않으면 외국인이 한국말을 하는 것처럼 들리니 반드시 추가해야 합니다.• None 함수 정의: 함수는 ** **와 ** **을 인수로 사용합니다. 입력된 텍스트는 음성으로 변환됩니다.• None 음성 생성 및 저장: 함수 내에서 텍스트를 전달하여 gTTS 인스턴스를 생성합니다. 그런 다음 메소드를 사용하여 ** **으로 지정된 MP3 파일로 음성을 출력합니다.IDE를 통해 또는 터미널에서 다음을 입력하여 Python 스크립트를 실행합니다.이렇게 하면 스크립트에 작성한 텍스트를 재생하는 MP3 파일이 디렉토리에 생성됩니다.이러한 단계를 통해 Python 및 gTTS를 사용하여 간단한 텍스트 음성 변환 애플리케이션을 만들었습니다.이는 텍스트 파일 읽기 또는 다른 응용 프로그램과의 통합과 같은 더 복잡한 기능으로 확장될 수 있습니다.다음에는 5분이상 길이의 스크립트를 음성으로 만든다면 어떻게 해야 할까요?기존에는 웹스크랩핑으로 텍스트를 긁어와서 파일을 만들었다면 이제는 ChatGPT에게 요청하여 만들 수 있습니다.ChatGPT를 이용하면 스크립트의 주제나 내용을 구체적으로 요청할 수 있는 장점이 있습니다.요청에 결과는 아래처럼 파일로 작성되었습니다. (버전 4로 만든내용입니다.)이제 만들어진 'Shampoo_Advertisement_Conversation.txt' 파일을 읽어서 mp3로 만들어봅니다.Python에서 MP3 파일을 재생하려면 'playsound' 모듈을 사용하면 됩니다.이는 오디오 재생을 처리하는 간단하고 직접적인 방법입니다. 방법은 다음과 같습니다.만약 설치할때 오류가 발생한다면 아래 2개도 함께 설치합니다.위의 코드에 playsound를 추가합니다.이렇게 하면 음성파일을 만들어서 매번 만들어졌는지 실행할 필요없이 바로 확인이 가능합니다.play를 종료하고자 한다면 실행 터미널에서 crtl +C 를 누릅니다.chatGPT를 이용하여 다시 코드로 복귀하는 불편함은 바로 api key를 이용하여 openai api 를 사용할 수 있습니다.그런데 chatgpt 비용과 platform 비용이 별도라 비용이 두배로 든다는 것은 참고해야 합니다.이렇게 하면 바로 mp3 파일이 생성되고 실행도 됩니다. 여기에 스크립트
python
SK텔레콤
CPython 3.13버전에서 기대되는 기능(A Per-Interpreter GIL)
이번에는 소스코드 뜯어보기가 아니라 차기 Python버전에서 기대되는 기능에 대해서 소개해 드릴려고 합니다 :)이번에 다뤄볼 내용은 what's new in python 3.12에서 등장한 A Per-interpreter GIL입니다.GIL은 Global Interpreter Lock의 약자로, Python Interpreter는 lock이 존재하고한순간에 하나의 프로그램(=Thread)만이 인터프리터를 사용할 수 있게 설계되어있습니다.때문에 MultiThread를 사용해서 한순간에 하나의 Core이상 사용하지 못하는 치명적인 단점을 가지고 있습니다.현재 MultiCore위주로 발전하고있는 CPU시장에서, single core만 활용할 수 있는 Python의 약점이 계속 커지고 있죠.per-Interpreter GIL은 이름으로 알 수 있지만interpreter마다 GIL을 갖게 만드는 것입니다.3.12에 실험 모드로 도입(PEP684) 되었으며3.13버전에 Python Level에서 사용할 수 있게 추가될 것으로 예상(PEP554)되는 기능 입니다.위 기능에 대한 PEP684를 잠깐 보겠습니다.주요하게 볼 점은, 입니다.결국 한순간에 두개 이상의 core를 사용할 수 있게 만들어 줌으로써 GIL의 단점을 상쇄할 수 있는 것이라고 설명되어 있습니다.안타깝게도 현재는 C-API로만 3.12버전에서 활용해 볼 수 있고, 3.13버전에서 실제 패키지 형태로 추가될 것으로 예상(subinterpreter Module)됩니다.이렇게만 글을 마무리 하기 아쉽죠?PEP-684 를 통해서 A-per Interpreter GIL가 어떻게 동작하는지 한번 요약해보면 아래와 같습니다.• None 이중 과거PEP-554에서 제시한 다중 인터프리터 관련 내용에여 영감을 받음• None 이를 개선하기 위해서 C-API를 수정해서 Global runtime에 대한 state를 격리시키고, 다른 state변수들은 PyInterpreterState로 올린다음 GIL을 한단계 인터프리터 수준까지 내리는 내용을 포함결국 Python Runtime에서 관리하던 GIL을 PyInterpreter수준으로 내리고Python Runtime에서는 다수의 Interpreter를 활용하여 multicore의 장점을 최대화 하려는 움직임으로 예상이 됩니다.앵 이거 걍 Process 새로 따는거 아뇨?🤔라고 생각할만 하지만, PEP 내에서 명백히 Process와는 다르다고 명시해 주고 있습니다.일반적인 프로그래밍 에서는의 형태를 가지고 있지만의 형태를 가지고 있다고 봐야할것 같습니다.Thread와 Interpreter가 모두 Process내에서 돌아가지만 Thread 끼리는 메모리를 공유하지만, Interpreter끼리는 격리가 되어서 메모리를 각자 관리한다가 큰 차이점으로 보입니다. 현재는 Thread만 Python Level에서 다룰 수 있고, interpreter는 3.13버전에서 추가될 것으로 예상됩니다.그래서 subinterpreter를 적용한 Test버전에서 성능평가를 할 때
python
Copyright © 2024. Codenary All Rights Reserved.