<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>won park님의 블로그</title>
    <link>https://infobox01219.tistory.com/</link>
    <description>상원공원님의 블로그 입니다.</description>
    <language>ko</language>
    <pubDate>Thu, 4 Jun 2026 17:13:08 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>상원공원</managingEditor>
    <image>
      <title>won park님의 블로그</title>
      <url>https://tistory1.daumcdn.net/tistory/8596447/attach/6d2e89519e0b4e7bbabfb0a300db9b59</url>
      <link>https://infobox01219.tistory.com</link>
    </image>
    <item>
      <title>Rate Limiting 정리</title>
      <link>https://infobox01219.tistory.com/6</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;6-1. 대규모 트래픽 설계&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스를 운영하다 보면 특정 순간에 엄청난 양의 요청이 몰릴 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 로그인 API, 게시글 조회 API, AI 모델 호출 API 등에 수천 명의 사용자가 동시에 접근하면 서버가 버티지 못할 수도 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 대규모 트래픽 환경에서는 서버를 보호하기 위한 다양한 기법을 사용하게 되는데, 그중 가장 기본적인 기술 중 하나가 &lt;b&gt;Rate Limiting&lt;/b&gt; 임 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Rate Limiting 이란 ?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Rate Limiting은 일정 시간 동안 허용 가능한 요청 수를 제한하는 기술임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 말하면 사용자가 API를 너무 많이 호출하지 못하도록 제한을 거는 것이라고 생각하면 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1분 동안 최대 10회 요청 허용&lt;/li&gt;
&lt;li&gt;1시간 동안 최대 1000회 요청 허용&lt;/li&gt;
&lt;li&gt;하루 동안 최대 10000회 요청 허용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 방식으로 설정할 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OpenAI API, GitHub API, AWS API 등 대부분의 서비스들이 사용하고 있음 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 왜 사용하는 걸까 ?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 요청 제한이 없다면 어떤 일이 발생할까 ?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 명의 사용자가 초당 수천 번 요청을 보내도 서버는 전부 처리하려고 시도하게 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 CPU 사용량이 폭증하고 DB 연결이 가득 차면서 정상 사용자까지 피해를 입게 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 Rate Limiting을 통해 서버를 보호하게 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;목적&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;서버 보호&lt;/td&gt;
&lt;td&gt;과도한 요청 차단&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;비용 절감&lt;/td&gt;
&lt;td&gt;불필요한 API 호출 감소&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DDoS 대응&lt;/td&gt;
&lt;td&gt;비정상 트래픽 완화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;공정성 확보&lt;/td&gt;
&lt;td&gt;특정 사용자의 독점 방지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;시스템 안정성&lt;/td&gt;
&lt;td&gt;전체 서비스 품질 유지&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 동작 방식&lt;/h3&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;
사용자 요청
      &amp;darr;
현재 요청 횟수 확인
      &amp;darr;
허용 횟수 초과 ?
   ↙        ↘
아니오         예
 &amp;darr;             &amp;darr;
요청 처리    429 에러 반환&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;429 Too Many Requests 는 요청 횟수 제한을 초과했다는 의미의 HTTP 상태 코드임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. FastAPI 메모리 기반 Rate Limiting&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 단순한 방식은 Python 메모리에 요청 기록을 저장하는 방법임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학습용 프로젝트에서는 충분히 사용할 수 있음 !&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;
from fastapi import FastAPI, Request, HTTPException
import time

app = FastAPI()

request_log = {}

@app.get(&quot;/&quot;)
def home(request: Request):

    ip = request.client.host
    now = time.time()

    if ip not in request_log:
        request_log[ip] = []

    request_log[ip] = [
        t for t in request_log[ip]
        if now - t &amp;lt; 60
    ]

    if len(request_log[ip]) &amp;gt;= 1000:
        raise HTTPException(
            status_code=429,
            detail=&quot;Too Many Requests&quot;
        )

    request_log[ip].append(now)

    return {&quot;message&quot;: &quot;success&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드는 1분 동안 최대 1000번 요청만 허용함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6번째 요청부터는 429 에러를 반환하게 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;메모리 방식의 문제점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버 재시작 시 데이터 유실&lt;/li&gt;
&lt;li&gt;멀티 서버 환경 불가능&lt;/li&gt;
&lt;li&gt;메모리 사용량 증가&lt;/li&gt;
&lt;li&gt;확장성 부족&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 실제 서비스에서는 잘 사용하지 않음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. FastAPI + Redis 기반 Rate Limiting&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서는 대부분 Redis를 사용함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redis는 메모리 기반 Key-Value 저장소이며 매우 빠르게 카운터를 관리할 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 여러 대의 서버가 동일한 Redis를 사용할 수 있어서 분산 환경에서도 안정적으로 동작함.&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;
from fastapi import FastAPI, Request, HTTPException
import redis

app = FastAPI()

r = redis.Redis(
    host=&quot;localhost&quot;,
    port=6379,
    decode_responses=True
)

@app.get(&quot;/&quot;)
def home(request: Request):

    ip = request.client.host

    key = f&quot;rate:{ip}&quot;

    count = r.incr(key)

    if count == 1:
        r.expire(key, 60)

    if count &amp;gt; 1000:
        raise HTTPException(
            status_code=429,
            detail=&quot;Too Many Requests&quot;
        )

    return {&quot;message&quot;: &quot;success&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redis의 incr() 는 값을 1 증가시키는 명령어임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;expire() 를 사용하여 60초 뒤 자동으로 삭제되도록 설정할 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 1분 동안 요청 횟수를 카운트하는 구조라고 생각하면 됨 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;만약 직접 트래픽을 확인해보고 싶다면 Locust를 사용해봐도 댐. (내가해봄...)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1780399826688&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;uvicorn main:app --host 0.0.0.0 --port 8000 --reload&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;일단 FastAPI 서버를 실행하고 ,&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1780399861636&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from locust import HttpUser, task, between

class RateLimitTestUser(HttpUser):
    wait_time = between(0.1, 0.5)

    @task
    def call_root_api(self):
        self.client.get(&quot;/&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Locust 코드르 짜서&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1780399887671&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;locust -f locustfile.py&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로 실행한다음 localhost:8089 들어가서&lt;br /&gt;localhost:8000번으로 쏴보면댐 . 위 FastAPI 코드는&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;1분 동안 최대 1000번 요청만 수락하니 . 1분에 1001번이 넘으면 429를 반환할거임 ㅇㅈ ?&amp;nbsp;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-06-02 오후 8.43.07.png&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;454&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TGGwe/dJMcaiKgqG1/ImoIhoPbzCfEOm8y0tI3C0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TGGwe/dJMcaiKgqG1/ImoIhoPbzCfEOm8y0tI3C0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TGGwe/dJMcaiKgqG1/ImoIhoPbzCfEOm8y0tI3C0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTGGwe%2FdJMcaiKgqG1%2FImoIhoPbzCfEOm8y0tI3C0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1004&quot; height=&quot;454&quot; data-filename=&quot;스크린샷 2026-06-02 오후 8.43.07.png&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;454&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;이렇게됌 ㅇㅇ...&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. 메모리 방식 vs Redis 방식&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;항목&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;메모리&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Redis&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;속도&lt;/td&gt;
&lt;td&gt;매우 빠름&lt;/td&gt;
&lt;td&gt;매우 빠름&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;서버 재시작&lt;/td&gt;
&lt;td&gt;데이터 유실&lt;/td&gt;
&lt;td&gt;유지 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;멀티 서버&lt;/td&gt;
&lt;td&gt;불가능&lt;/td&gt;
&lt;td&gt;가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;운영 환경&lt;/td&gt;
&lt;td&gt;비추천&lt;/td&gt;
&lt;td&gt;권장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;확장성&lt;/td&gt;
&lt;td&gt;낮음&lt;/td&gt;
&lt;td&gt;높음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;정리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Rate Limiting은 대규모 트래픽 환경에서 서버를 보호하기 위한 가장 기본적인 기술 중 하나임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과도한 요청을 차단하여 시스템의 안정성을 유지하고, 모든 사용자에게 공정한 서비스를 제공할 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학습 단계에서는 메모리 방식으로 충분하지만 실제 서비스에서는 Redis 기반 Rate Limiting을 사용하는 경우가 대부분이라고 생각하면 됨 !&lt;/p&gt;</description>
      <category>시스템 설계 (System Design)/대규모 트래픽 설계</category>
      <author>상원공원</author>
      <guid isPermaLink="true">https://infobox01219.tistory.com/6</guid>
      <comments>https://infobox01219.tistory.com/6#entry6comment</comments>
      <pubDate>Tue, 2 Jun 2026 20:43:56 +0900</pubDate>
    </item>
    <item>
      <title>vLLM 세팅 및 기술들</title>
      <link>https://infobox01219.tistory.com/5</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;무거운 모델들을 &lt;b&gt;어떻게 렉 없이 초고속으로 굴릴 것인가&lt;/b&gt;에 대해 알아봅시다&lt;br /&gt;&lt;br /&gt;로컬에서 오픈소스 LLM을 서비스하려고 할 때 무조건 짚고 넘어가야 하는 핵심 엔진, 바로 &lt;b&gt;vLLM&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;1. Continuous Batching (쉬지 않고 일함 노동...ㅋ)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: 앞사람의 질문이 끝날 때까지 기다리지 않고, 빈자리가 생기면 실시간으로 다음 사람의 토큰을 끼워 넣어서 처리하는 기법임.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;원리&lt;/b&gt;: 기존에는 3명이 질문하면 제일 긴 답변이 끝날 때까지 다 같이 기다려야 했음(Static Batching). 근데 Continuous Batching은 짧은 답변이 먼저 끝나면 바로 그 자리에 4번째 사람의 질문을 밀어 넣음. GPU가 1초도 쉬지 않게 풀가동 돌려버리는 거임 !&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;2. PagedAttention (ㄹㅇ 진짜 핵심! vLLM의 존재 이유)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vLLM에서 'v'가 Virtual(가상)의 약자임 !!!! 이게 바로 컴퓨터 운영체제의 가상 메모리(Virtual Memory) 개념을 LLM에 끌고 온 거임!&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기존의 문제점&lt;/b&gt;: AI가 대화의 문맥을 기억하려고 메모리(KV Cache)를 엄청 쓰는데, 원래는 이걸 '이만큼 쓰겠지?' 하고 무식하게 통째로 미리 잡아뒀음. 그래서 빈 공간이 펑펑 낭비되고, 유저 몇 명만 들어와도 GPU 메모리가 꽉 차서 뻗어버림 (OOM 에러 발생).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;해결 원리&lt;/b&gt;: 통째로 잡지 말고, 메모리를 '페이지(Page)'라는 아주 작은 블록으로 잘게 쪼개서 관리함. 필요할 때마다 블록을 딱딱 할당해주니까 낭비되는 메모리가 거의 제로에 수렴함. 덕분에 &lt;b&gt;똑같은 GPU 사양으로 훨씬 더 많은 사람의 요청을 동시에 버틸 수 있게 됨 !&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;3. KV Cache Reuse (캐시 재사용)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: 공통적으로 들어가는 시스템 프롬프트(예: &quot;너는 친절한 회사 CS 비서야&quot;)를 매번 새로 계산하지 않고, 한 번 계산해둔 걸 기억했다가 복붙해서 쓰는 거임.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;효과&lt;/b&gt;: 사용자가 질문을 던졌을 때 AI가 첫 글자를 뱉어내는 속도(TTFT)가 미친 듯이 빨라짐. 굳이 했던 연산 또 안 하니까 돈도 굳고 시간도 굳음!&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KV Cache Reuse는 최적화할때 많이 사용한다고 들었음.&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;코드로 보는 vLLM 세팅 !&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;vLLM 구동 및 최적화 예시 코드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1779448999999&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from vllm import LLM, SamplingParams

# 모델 이름만 넣어주면 Continuous Batching이랑 PagedAttention은 알아서 가동댐
llm = LLM(
    model=&quot;meta-llama/Llama-3-8b-Instruct&quot;,
)

#샘플링파라미터들은 아래 링크 참고하기 !
sampling_params = SamplingParams(temperature=0.7, top_p=0.95)


prompts = [
    &quot;ㅎㅇ? 넌 누구야?&quot;,
    &quot;회사 서버에 AI 구축할 때 주의할 점 3가지만 알려달라.&quot;
]

# 한 방에 여러 개 던져도 PagedAttention 덕에 괜찮음
outputs = llm.generate(prompts, sampling_params)

for output in outputs:
    prompt = output.prompt
    generated_text = output.outputs[0].text
    print(f&quot;질문: {prompt}\n답변: {generated_text}\n---&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* vLLM SamplingParams 링크&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.vllm.ai/en/latest/api/vllm/sampling_params/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.vllm.ai/en/latest/api/vllm/sampling_params/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;대체로 코딩용은 이런식으로 작성&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1780163940410&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SamplingParams(
    temperature=0.1,
    top_p=0.9,
    repetition_penalty=1.05,
    max_tokens=2048
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;대체로 챗봇용은 이런식으로 작성&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1780163977876&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SamplingParams(
    temperature=0.7,
    top_p=0.95,
    max_tokens=1024
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사내 데이터를 다뤄야 해서 API 연동은 안 되고 로컬 모델을 돌려야 할 때, 혹은 비싼 클라우드 GPU 비용을 어떻게든 뽕뽑아야 할 때 &lt;b&gt;vLLM&lt;/b&gt;은 선택이 아니라 필수라고 생각함&lt;/p&gt;
&lt;p data-path-to-node=&quot;31&quot; data-ke-size=&quot;size16&quot;&gt;그냥 순정으로 모델 다운받아서 쓰는 거랑은 차원이 다른 엔터프라이즈급 처리량을 보여주니까, 기업용 AI 아키텍처를 설계한다면 무조건 도입하는 해야되지 않을까 라는 생각이 듬 !!&lt;/p&gt;
&lt;p data-path-to-node=&quot;31&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;31&quot; data-ke-size=&quot;size16&quot;&gt;아무튼 vLLM의 핵심 기술들에 대해 알아보았음 !&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignLeft&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;023&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/friends1/large/023.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/friends1/large/023.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;</description>
      <category>AI 모델 서빙 (AI Serving)/vLLM Deep Dive</category>
      <category>PagedAttention</category>
      <category>vLLM</category>
      <category>자기개발</category>
      <category>파이썬</category>
      <author>상원공원</author>
      <guid isPermaLink="true">https://infobox01219.tistory.com/5</guid>
      <comments>https://infobox01219.tistory.com/5#entry5comment</comments>
      <pubDate>Sun, 31 May 2026 03:02:24 +0900</pubDate>
    </item>
    <item>
      <title>프로파일링(Profiling)으로 병목 지점 찾는 법</title>
      <link>https://infobox01219.tistory.com/4</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;[파이썬 성능 최적화 #1]&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 파이썬 내장 도구인 cProfile과 강력한 라인별 분석 도구인 line_profiler를 활용해, 느려진 코드의 원인을 검거하는 방법을 알아보겠음 !!!!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #424242; text-align: start;&quot;&gt;cProfile은 파이썬 코드의 실행 시간을 함수 단위로 측정해 병목을 찾는 프로파일러임 !! &lt;br /&gt;cProfile은 파이썬 내장 표준 라이브러리 라서 pip 없이 사용 가능합니둥&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #424242; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #424242; text-align: start;&quot;&gt;line_profiler 는 설치해야댐 ...&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1779777197379&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip install line_profiler&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #424242; text-align: start;&quot;&gt;예시 코드: 알고리즘 함수에서 어떤 코드가 느린지 찾고 싶을 때&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1779776621621&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import cProfile
import random
import time

#일부러 1초 기다렸다가 정렬하도록 예시들겠음.
def slow(arr):
    time.sleep(1) 
    return sorted(arr)

#빠르게 arr에다가 2만 곱하는 함수로 예시들겠음
def fast(arr):
    return [x * 2 for x in arr]

# slow 와 fast를 cProfile을 이용해 비교하면 병목이 누군지 나오겠죠 ??

#랜덤으로 10000개 숫자 만들고 함수를 호출해보겠음 !!
def main():
    data = [random.randint(1, 1000) for _ in range(10000)]
    res1 = fast(data)
    res2 = slow(data)

if __name__ == &quot;__main__&quot;:
    cProfile.run('main()')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드를 돌려보면&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1779778317271&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;python3 app.py           
         80257 function calls in 1.018 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    1.018    1.018 &amp;lt;string&amp;gt;:1(&amp;lt;module&amp;gt;)
        1    0.000    0.000    0.000    0.000 app.py:11(fast)
        1    0.000    0.000    0.000    0.000 app.py:12(&amp;lt;listcomp&amp;gt;)
        1    0.000    0.000    1.018    1.018 app.py:17(main)
        1    0.002    0.002    0.012    0.012 app.py:18(&amp;lt;listcomp&amp;gt;)
        1    0.000    0.000    1.006    1.006 app.py:6(slow)
    10000    0.002    0.000    0.003    0.000 random.py:235(_randbelow_with_getrandbits)
    10000    0.005    0.000    0.009    0.000 random.py:284(randrange)
    10000    0.002    0.000    0.010    0.000 random.py:358(randint)
    30000    0.001    0.000    0.001    0.000 {built-in method _operator.index}
        1    0.000    0.000    1.018    1.018 {built-in method builtins.exec}
        1    0.001    0.001    0.001    0.001 {built-in method builtins.sorted}
        1    1.005    1.005    1.005    1.005 {built-in method time.sleep}
    10000    0.000    0.000    0.000    0.000 {method 'bit_length' of 'int' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
    10247    0.000    0.000    0.000    0.000 {method 'getrandbits' of '_random.Random' objects}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 결과가 나오는데&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 봐야될건 !&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,0,0&quot;&gt;ncalls (Number of Calls):&lt;/b&gt; 함수가 몇 번이나 호출되었는가?&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,1,0&quot;&gt;tottime (Total Time):&lt;/b&gt; 그 함수 '자체'가 순수하게 소비한 시간 (내가 부른 다른 함수 시간은 제외)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,0,2,0&quot;&gt;percall&lt;/b&gt;: 그래서 &lt;b data-index-in-node=&quot;13&quot; data-path-to-node=&quot;20,0,2,0&quot;&gt;평균적으로 한 번 실행될 때 몇 초&lt;/b&gt; 걸렸는가? (평균 속도)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자 ! 하나씩 해석해보자면 .&lt;/p&gt;
&lt;pre id=&quot;code_1779779114321&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
	1    1.005    1.005    1.005    1.005 {built-in method time.sleep}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분이 문제라는걸 알 수 있는데 (시간이 가장 오래걸렸으니까 !)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보기가&amp;nbsp; 좀 어려움 ... 헷갈림 ... 만약 이런 대충짠 코드가 아닌 제대로 만든 코드였다면 다른곳은 30초 50초 ~~~ 이렇게 넓게 분포되어있을태니까 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 필요한 라인만 편하게 볼 수 있고 , 퍼센트까지 알수있는 line_profiler를 보면 (&lt;b&gt;pip install line_profiler&lt;/b&gt; 해야댐)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #424242; text-align: start;&quot;&gt;예시 코드&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #424242; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1779787493878&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import random
import time

# @profile로 의심이 가는 부분 데코레이터
@profile
def slow(arr):
    time.sleep(1)
    return sorted(arr)

# @profile로 의심이 가는 부분 데코레이터
@profile
def main():
    data = [random.randint(1, 1000) for _ in range(10000)]
    res1 = fast(data)
    res2 = slow(data)

def fast(arr):
    return [x * 2 for x in arr]

if __name__ == &quot;__main__&quot;:
    main()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 실행은 python3 app.py 가 아닌&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1779789163506&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kernprof -l -v app.py&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로 실행하기 !&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-path-to-node=&quot;7,0,0&quot; data-index-in-node=&quot;0&quot;&gt;kernprof (Kernel Profiler):&lt;/b&gt;&lt;span&gt; 정밀 타이머가 내장된 &lt;b data-index-in-node=&quot;12&quot; data-path-to-node=&quot;21,2,2,0&quot;&gt;특수 파이썬 실행기&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-path-to-node=&quot;7,1,0&quot; data-index-in-node=&quot;0&quot;&gt;-l (&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;21,3,1,0&quot;&gt;L&lt;/b&gt;ine-by-line):&lt;/b&gt;&lt;span&gt;&lt;b&gt; 함수&lt;/b&gt; 말고 &lt;b&gt;코드 줄 단위&lt;/b&gt;로 쪼개서 측정하라는 명령어&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;-v (&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;21,4,1,0&quot;&gt;V&lt;/b&gt;iew)&lt;/b&gt; : 결과를 파일로 만들어 저장하지말고 &lt;b&gt;터미널&amp;nbsp;&lt;/b&gt;로 결과를 보여주라는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 결과를 보면 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1779789781243&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kernprof -l -v app.py
Timer unit: 1e-06 s

Total time: 1.00644 s [Function: slow at line 5]
Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     5                                           @profile
     6                                           def slow(arr):
     7         1    1005083.0 1.01e+06     99.9      time.sleep(1)
     8         1       1356.0   1356.0      0.1      return sorted(arr)

Total time: 1.01809 s [Function: main at line 11]
Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    11                                           @profile
    12                                           def main():
    13         1      11058.0  11058.0      1.1      data = [random.randint(1, 1000) for _ in range(10000)]
    14         1        495.0    495.0      0.0      res1 = fast(data)
    15         1    1006540.0 1.01e+06     98.9      res2 = slow(data)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 퍼센트별로 나오는걸 볼 수 있음 !&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 메모리때문에 터지는걸 알고싶다면 ! &lt;b&gt;memory_profiler&lt;/b&gt; 로 사용하면 됌 .&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용법은 똑같음 !&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리해보자면 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 data-path-to-node=&quot;3&quot;&gt;파이썬 프로파일러 비교 요약&lt;/h1&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;4&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;비교 항목&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;  cProfile (거시적 분석)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;  line_profiler (미시적 분석)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4,1,0,0&quot;&gt;핵심 역할&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,1,1,0&quot;&gt;프로그램 전체를 조망하며 &lt;b data-index-in-node=&quot;14&quot; data-path-to-node=&quot;4,1,1,0&quot;&gt;느린 함수&lt;/b&gt; 찾기&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,1,2,0&quot;&gt;지정한 함수 내부에서 &lt;b data-index-in-node=&quot;12&quot; data-path-to-node=&quot;4,1,2,0&quot;&gt;느린 코드 줄(Line)&lt;/b&gt; 찾기&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4,2,0,0&quot;&gt;분석 단위&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,2,1,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4,2,1,0&quot;&gt;함수(Function) 단위&lt;/b&gt; 통계&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,2,2,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4,2,2,0&quot;&gt;코드 줄(Line) 단위&lt;/b&gt; 상세 분석&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4,3,0,0&quot;&gt;설치 여부&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,3,1,0&quot;&gt;파이썬 &lt;b data-index-in-node=&quot;4&quot; data-path-to-node=&quot;4,3,1,0&quot;&gt;내장&lt;/b&gt; 라이브러리 (설치 필요 없음)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,3,2,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4,3,2,0&quot;&gt;외장&lt;/b&gt; 라이브러리 (pip install line_profiler)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,4,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4,4,0,0&quot;&gt;코드 수정&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,4,1,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4,4,1,0&quot;&gt;필요 없음&lt;/b&gt; (명령어 한 줄로 바로 실행)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,4,2,0&quot;&gt;분석할 함수 위에 &lt;b data-index-in-node=&quot;10&quot; data-path-to-node=&quot;4,4,2,0&quot;&gt;@profile 데코레이터 필수&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,5,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4,5,0,0&quot;&gt;실행 명령어&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,5,1,0&quot;&gt;python3 -m cProfile -s cumtime app.py&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,5,2,0&quot;&gt;kernprof -l -v app.py&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,6,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4,6,0,0&quot;&gt;핵심 지표&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,6,1,0&quot;&gt;cumtime (함수가 소모한 총 누적 시간)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,6,2,0&quot;&gt;% Time (해당 줄이 차지한 시간 지분율)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,7,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4,7,0,0&quot;&gt;성능 오버헤드&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,7,1,0&quot;&gt;비교적 가볍고 빠름&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,7,2,0&quot;&gt;한 줄씩 측정하므로 프로그램이 &lt;b data-index-in-node=&quot;17&quot; data-path-to-node=&quot;4,7,2,0&quot;&gt;수십 배 느려짐&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,8,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4,8,0,0&quot;&gt;현업의 추천 흐름&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,8,1,0&quot;&gt;1단계: &lt;b data-index-in-node=&quot;5&quot; data-path-to-node=&quot;4,8,1,0&quot;&gt;용의자 함수&lt;/b&gt;를 빠르게 색출할 때&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;4,8,2,0&quot;&gt;2단계: 색출된 함수 내의 &lt;b data-index-in-node=&quot;15&quot; data-path-to-node=&quot;4,8,2,0&quot;&gt;진범 줄&lt;/b&gt;을 저격할 때&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;병목을 찾고싶을때 사용할 것 !!!!!!&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;014&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/friends1/large/014.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/friends1/large/014.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;</description>
      <category>백엔드 엔지니어링(Backend Engineering)/Python 심화</category>
      <author>상원공원</author>
      <guid isPermaLink="true">https://infobox01219.tistory.com/4</guid>
      <comments>https://infobox01219.tistory.com/4#entry4comment</comments>
      <pubDate>Tue, 26 May 2026 19:07:55 +0900</pubDate>
    </item>
    <item>
      <title>Chain of Thought(CoT) , ReAct(Reasoning + Acting) 정리</title>
      <link>https://infobox01219.tistory.com/3</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;AI가 어려운 문제를 풀기 위해서 제대로 생각하는 방법에 대해 생각해봅시다앙.&lt;br /&gt;&lt;br /&gt;복잡한 논리 구조나 외부 데이터가 필요한 시점부터는 Chain of Thought(CoT)와 ReAct(리액트)가 핵심 엔진임 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot; data-path-to-node=&quot;6&quot;&gt;1. Chain of Thought (Langchain같은 느낌이라고 생각하면 될듯 chain으로 엮어 !)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: 모델에게 곧바로 최종 정답을 요구하지 않고, 문제를 해결하기 위한 중간 단계의 논리적 추론 과정을 순서대로 거쳐 답을 내도록 유도하는 기법임.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;원리&lt;/b&gt;: 문장제 수학 문제나 수수께끼를 풀 때 연습장에 풀이 과정을 적어가며 정답률을 높이는 것처럼, LLM에게 생각과 논리적 흐름을 제공하여 정답 도출 확률을 높임.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-path-to-node=&quot;6&quot; data-ke-size=&quot;size23&quot;&gt;1. ReAct (React랑 헷갈리면 안댑니다)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,0,0&quot;&gt;정의:&lt;/b&gt; CoT의 추론(Reasoning) 능력에 외부 환경과 상호작용하는 &lt;b data-index-in-node=&quot;43&quot; data-path-to-node=&quot;7,0,0&quot;&gt;행동(Acting)&lt;/b&gt;&amp;nbsp;능력을 결합하여, 스스로 판단하고 필요한 도구를 꺼내 쓰게 만드는 기법임.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,1,0&quot;&gt;원리:&lt;/b&gt; LLM이 내부적으로 [Thought(생각) -&amp;gt; Act(행동) -&amp;gt; Observation(관찰)]이라는 루프를 독립적으로 반복하며, 자신이 모르는 정보가 나오면 검색이나 계산기 등의 툴을 자율적으로 구동하여 최종 결론 생성함&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot; data-path-to-node=&quot;6&quot;&gt;코드로 보여주는게 이해가 빠를 거 같음 !&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Cot 예시 코드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1779448442158&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    api_key=&quot;your_api_key_here&quot;,
    model=&quot;gpt모델입력 ㄱ&quot;
)

cot_prompt = &quot;&quot;&quot;
질문:  &quot;어떤 농장에 닭과 토끼가 합쳐서 12마리 있습니다. 다리 수를 모두 세어보니 32개. 토끼는 몇 마리일까요??&quot;

질문에 대해 단계별로 차근차근 생각 과정을 적은 뒤, 최종 정답 입력해주세요.
&quot;&quot;&quot;

response = llm.invoke(cot_prompt)
print(response.content)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ReAct 예시 코드&lt;/p&gt;
&lt;pre id=&quot;code_1779448553755&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    api_key=&quot;your_api_key_here&quot;,
    model=&quot;gpt모델입력 ㄱ&quot;
)

react_prompt = &quot;&quot;&quot;
당신은 질문을 해결하기 위해 생각(Thought)하고, 도구를 선택해 행동(Act)하고, 그 결과물인 관찰(Observation)을 통해 최종 답을 도출해야 합니다.

사용 가능한 도구:
1. Google_Search: 최신 정보나 상식을 검색할 때 사용.
2. Calculator: 수학적인 계산이 필요할 때 사용.

출력 형식:
Thought: 문제를 풀기 위해 지금 해야 하는 생각
Act: 사용할 도구 이름 [도구에 넣을 입력값]
Observation: 도구의 실행 결과 (이 부분은 외부 시스템이 채워줄 것임)
... (이 과정을 반복)
Final Answer: 최종 정답

질문: 2026년 현재 대한민국 대통령의 나이에 5를 곱하면 얼마인가요?
Thought:
&quot;&quot;&quot;
#AI의 힘을 빌려버리긔

response = llm.invoke(react_prompt)
print(response.content)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;26&quot; data-ke-size=&quot;size23&quot;&gt;5. 두 개념 한눈에 비교&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;27&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;비교 항목&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Chain of Thought (CoT)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;ReAct&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;27,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;27,1,0,0&quot;&gt;핵심 메커니즘&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;27,1,1,0&quot;&gt;속으로 차근차근 풀이 과정 출력하기&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;27,1,2,0&quot;&gt;차근차근 생각하면서 외부 도구(Tool) 연동하기&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;27,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;27,2,0,0&quot;&gt;작동 영역&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;27,2,1,0&quot;&gt;LLM 내부의 기억 공간 (닫힌 세계)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;27,2,2,0&quot;&gt;LLM 외부 환경 + 인터넷/시스템 (열린 세계)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;27,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;27,3,0,0&quot;&gt;주요 목적&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;27,3,1,0&quot;&gt;고차원적인 논리 및 수학 연산 능력 고도화&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;27,3,2,0&quot;&gt;환각 현상 극복 및 실시간 정확한 데이터 확보&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;27,4,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;27,4,0,0&quot;&gt;토큰 소모량&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;27,4,1,0&quot;&gt;보통 (출력 텍스트 증가분만큼 추가)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;27,4,2,0&quot;&gt;높음 (루프 반복 및 툴 결과물이 계속 누적)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;27,5,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;27,5,0,0&quot;&gt;적합한 작업&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;27,5,1,0&quot;&gt;IQ 테스트, 수수께끼, 코드 검증, 다단계 수학 문제&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;27,5,2,0&quot;&gt;실시간 날씨 기반 옷 추천, 최신 기업 정보 분석&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비즈니스 로직에 AI를 활용하려면 CoT와 ReAct는 사용해야 된다고 생각함 !&lt;/p&gt;
&lt;p data-path-to-node=&quot;31&quot; data-ke-size=&quot;size16&quot;&gt;단순히 모델 내부의 지식 구조를 끄집어내어 논리력을 높이고 싶다면&amp;nbsp; &lt;b data-index-in-node=&quot;56&quot; data-path-to-node=&quot;31&quot;&gt;CoT&lt;/b&gt;를 적용하는 것이 맞음. &lt;br /&gt;하지만 실시간 데이터 연동이 필수적이거나 기업 내부의 ERP, DB, 검색 엔진과 연결되어 스스로 일하는 에이전트를 만들고 싶다면 &lt;b data-index-in-node=&quot;146&quot; data-path-to-node=&quot;31&quot;&gt;ReAct&lt;/b&gt; 아키텍처를 도입하는 것이 더 좋아보임 !&lt;/p&gt;
&lt;p data-path-to-node=&quot;31&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;31&quot; data-ke-size=&quot;size16&quot;&gt;아무튼 CoT 와 ReAct에 대해 알아보았음 !&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignLeft&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;023&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/friends1/large/023.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/friends1/large/023.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;</description>
      <category>인공지능(AI)/생성형 AI &amp;amp; LLM</category>
      <category>cot</category>
      <category>React</category>
      <author>상원공원</author>
      <guid isPermaLink="true">https://infobox01219.tistory.com/3</guid>
      <comments>https://infobox01219.tistory.com/3#entry3comment</comments>
      <pubDate>Fri, 22 May 2026 20:16:47 +0900</pubDate>
    </item>
    <item>
      <title>Zero-shot(제로샷) vs Few-shot(퓨 샷) 정리</title>
      <link>https://infobox01219.tistory.com/2</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;생성형 AI와 LLM을 원하는 대로 조종하기 위해 가장 중요한 것이 프롬프트 엔지니어링임. &lt;br /&gt;&lt;br /&gt;그 중에서도 AI에게 예시를 주느냐 마느냐에 따라 나뉘는 &lt;b data-index-in-node=&quot;108&quot; data-path-to-node=&quot;3&quot;&gt;Zero-shot&lt;/b&gt;과 &lt;b data-index-in-node=&quot;119&quot; data-path-to-node=&quot;3&quot;&gt;Few-shot&lt;/b&gt;은 프롬프트 작성을 시작할 때 가장 먼저 마주하는 핵심 개념임.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;6&quot; data-ke-size=&quot;size23&quot;&gt;1. Zero-shot (제로부터 시작하는 이세카이)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;7&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,0,0&quot;&gt;정의:&lt;/b&gt; 모델에게 사전 예시를 전혀 제공하지 않고, 곧바로 질문이나 명령을 던져 답을 얻는 방식임.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,1,0&quot;&gt;원리:&lt;/b&gt; LLM이 이미 방대한 데이터로 사전 학습한 지식과 문맥 이해 능력만을 믿고 답을 출력하게 만듬.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size23&quot;&gt;2. Few-shot (힌트 주고 스따또)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;9&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,0,0&quot;&gt;정의:&lt;/b&gt; 모델에게 원하는 결과물의 형태, 스타일, 규칙을 담은 &lt;b data-index-in-node=&quot;34&quot; data-path-to-node=&quot;9,0,0&quot;&gt;몇 개 예시&lt;/b&gt;를 프롬프트에 포함하여 질문하는 방식임.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,1,0&quot;&gt;원리:&lt;/b&gt; 모델이 거대한 가중치를 바꾸는 파인튜닝을 거치지 않고도, 프롬프트 내부의 문맥 안에서 빠르게 학습하여 답변 정확도를 높임.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-path-to-node=&quot;8&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;이들을 사용하는 이유는&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM은 근본적으로 &lt;b&gt;다음에 올 가장 확률 높은 단어&lt;/b&gt;를 예측하는 기계임. 따라서 아무런 가이드라인이 없으면 엉뚱한 방향으로 답변을 출력하기 쉬움.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;13&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,0,0&quot;&gt;Zero-shot을 사용하는 이유:&lt;/b&gt; 인간이 당연하게 생각하는 상식적 작업이나 간단한 요약 등은 예시를 쓰는 시간조차 아깝기 때문임. 비용과 시간을 아끼면서 모델의 기본 성능을 테스트하기에 최적임.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,1,0&quot;&gt;Few-shot을 사용하는 이유:&lt;/b&gt; LLM에게 우리가 원하는 &lt;b&gt;특정 출력 형식&lt;/b&gt;이나 &lt;b&gt;비즈니스 룰&lt;/b&gt;을 강제하기 위함임. 말로 길게 설명하는 것보다 잘 짜인 예시 2~3개를 보여주는 것이 모델을 이해시키기 훨씬 훨씬 빠르기 때문임.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-path-to-node=&quot;15&quot; data-ke-size=&quot;size26&quot;&gt;3. 장점과 문제점 (좋은 점 &amp;amp; 나쁜 점)&lt;/h2&gt;
&lt;h3 data-path-to-node=&quot;16&quot; data-ke-size=&quot;size23&quot;&gt;Zero-shot&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;17&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,0,0&quot;&gt;좋은 점:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;17,0,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프롬프트 길이가 짧아 토큰비용이 매우 저렴함. ✅(핵심)&lt;/li&gt;
&lt;li&gt;예시를 고민할 필요가 없어 빠르게 결과를 도출할 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,1,0&quot;&gt;문제점:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;17,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;복잡한 논리 연산이나 특정 포맷을 정확히 맞춰야 하는 작업에서는 답변 성공률이 급격히 떨어짐.&lt;/li&gt;
&lt;li&gt;모델의 컨디션이나 무작위성때매 일관성이 부족함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;18&quot; data-ke-size=&quot;size23&quot;&gt;Few-shot&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;19&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,0,0&quot;&gt;좋은 점:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;19,0,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;출력 결과물의 형식을 90% 이상 일정하게 통제할 수 있음.&lt;/li&gt;
&lt;li&gt;어려운 추론 문제나 특수한 도메인 지식이 필요한 작업에서 정확도가 비약적으로 상승함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,1,0&quot;&gt;문제점:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;19,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예시가 늘어나는 만큼 입력 토큰을 많이 소비하므로 API 비용이 증가함.&lt;/li&gt;
&lt;li&gt;만약 예시에 오류나 편향된 내용이 포함되면, 모델이 그 잘못된 패턴까지 그대로 학습하여 엉터리 답을 출력함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-path-to-node=&quot;15&quot; data-ke-size=&quot;size26&quot;&gt;Zero-shot 코드 예시&lt;/h2&gt;
&lt;pre id=&quot;code_1779444543461&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
	api_key =&quot;llm사용할때 키 적기&quot; ,
    model =&quot;gpt 키 적기&quot; #gpt-4o
)
    
zero_shot_prompt = &quot;&quot;&quot;
감정분석한거 결과 적어라 
&quot;하 오늘 피곤하네 넘 열심히했나 맛있는거 먹으러가야지&quot;
&quot;&quot;&quot;

response = llm.invoke(zero_shot_prompt)
print(response.content)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-path-to-node=&quot;15&quot; data-ke-size=&quot;size26&quot;&gt;Few-shot 코드 예시&lt;/h2&gt;
&lt;pre id=&quot;code_1779444632690&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
	api_key =&quot;llm사용할때 키 적기&quot; ,
    model =&quot;gpt 키 적기&quot; #gpt-4o
)

few_shot_prompt = &quot;&quot;&quot;
당신은 감정 분석 전문가입니다. 아래 예시의 형식에 맞춰서 마지막 문장의 감정을 분석하세요.

문장: &quot;오늘 날씨가 너무 좋아서 산책 다녀왔어!&quot; -&amp;gt; 감정: 긍정
문장: &quot;기다리던 택배가 왔는데 물건이 파손되어 있네요.&quot; -&amp;gt; 감정: 부정
문장: &quot;점심에 밥먹구 친구들이랑 만나서 놀았어.&quot; -&amp;gt; 감정: 중립


문장: &quot;하 오늘 피곤하네 넘 열심히했나 맛있는거 먹으러가야지&quot;
감정:
#예시는 AI작품 ㅎ..
&quot;&quot;&quot;

response = llm.invoke(few_shot_prompt)
print(response.content)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;28&quot; data-ke-size=&quot;size26&quot;&gt;표로 정리해보자면 !&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;29&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;비교 항목&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Zero-shot&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Few-shot&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,1,0,0&quot;&gt;사전 예시 제공 여부&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,1,1,0&quot;&gt;없음 (0개)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,1,2,0&quot;&gt;있음 (보통 2~5개 내외)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,2,0,0&quot;&gt;토큰 소모량 (비용)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,2,1,0&quot;&gt;매우 적음&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,2,2,0&quot;&gt;많음 (예시 분량만큼 추가 지불)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,3,0,0&quot;&gt;답변의 일관성&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,3,1,0&quot;&gt;비교적 낮음 (매번 바뀔 수 있음)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,3,2,0&quot;&gt;매우 높음 (패턴을 복제함)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,4,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,4,0,0&quot;&gt;적합한 작업&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,4,1,0&quot;&gt;단순 요약, 번역, 일반적인 상식 Q&amp;amp;A&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,4,2,0&quot;&gt;데이터 구조화(json), 복잡한 수학/추론, 특정 톤앤매너 유지&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,5,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,5,0,0&quot;&gt;엔지니어링 공수&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,5,1,0&quot;&gt;프롬프트 작성이 간단함&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,5,2,0&quot;&gt;좋은 예시를 고르는 노력이 필요함&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;31&quot; data-ke-size=&quot;size26&quot;&gt;결론으로는&lt;/h2&gt;
&lt;p data-path-to-node=&quot;32&quot; data-ke-size=&quot;size16&quot;&gt;프롬프트 엔지니어링을 할 때는 &lt;b data-index-in-node=&quot;17&quot; data-path-to-node=&quot;32&quot;&gt;Zero-shot을 먼저 시도해보는 것이 순서임.&lt;/b&gt; Zero-shot만으로도 원하는 결과가 깨끗하게 잘 나온다면 비용과 속도 측면에서 가장 베스트이기 때문임. (근데 요즘 생성모델 성능이 넘 좋아서 ... 아마 Zero-shot으로 충분할겨)&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;33&quot; data-ke-size=&quot;size16&quot;&gt;하지만 모델이 자꾸 헛소리(환각 현상)를 하거나, 출력이 제멋대로 날뛰기 시작한다면 그때 잘 정돈된 예시를 꽂아 넣는 &lt;b data-index-in-node=&quot;66&quot; data-path-to-node=&quot;33&quot;&gt;Few-shot 전략으로 선회&lt;/b&gt;하는 것이 현명한 LLM 애플리케이션 개발 방향임.&lt;br /&gt;&lt;br /&gt;아무리 generation model 성능이 좋아졌어도 성능만 봤을 때는 &lt;b&gt;few-shot &amp;gt; zero-shot&lt;/b&gt; 이긴 함 . 성능을 올려야 될 때&lt;br /&gt;이런 프롬프트 엔지니어링을 해볼 것.&lt;/p&gt;</description>
      <category>인공지능(AI)/생성형 AI &amp;amp; LLM</category>
      <category>few shot</category>
      <category>llm</category>
      <category>Prompt Enginnering</category>
      <category>Zero shot</category>
      <category>개발공부</category>
      <category>개발자</category>
      <category>백엔드</category>
      <author>상원공원</author>
      <guid isPermaLink="true">https://infobox01219.tistory.com/2</guid>
      <comments>https://infobox01219.tistory.com/2#entry2comment</comments>
      <pubDate>Fri, 22 May 2026 19:26:24 +0900</pubDate>
    </item>
    <item>
      <title>GIL (Global Interpreter Lock)</title>
      <link>https://infobox01219.tistory.com/1</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;header-container&quot;&gt;
&lt;h1&gt;GIL (Global Interpreter Lock)&lt;/h1&gt;
&lt;div class=&quot;subtitle&quot;&gt;파이썬의 성능과 멀티스레딩을 이야기할 때 빼놓을 수 없는 핵심 개념, GIL 상세 분석 가이드&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. GIL이 무엇인가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;GIL(Global Interpreter Lock)&lt;/b&gt;은 파이썬 인터프리터(CPython)가 한 번에 하나의 스레드만 Python bytecode를 실행할 수 있도록 제한하는 &lt;b&gt;글로벌 락(Lock)&lt;/b&gt;입니다. 즉, 여러 개의 프로세서 코어가 있고 다중 스레드가 존재하더라도, 실제로 파이썬 코드는 동시에 실행되&lt;br /&gt;지 못하고 단 하나의 스레드만 실행 권한을 가집니다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 파이썬이 GIL을 사용하는 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPython은 메모리 관리를 위해 &lt;b&gt;레퍼런스 카운팅(Reference Counting)&lt;/b&gt; 방식을 사용합니다. 여러 스레드가 동시에 객체의 레퍼런스 카운트를 증가시키거나 감소시키면 대규모 데이터 경합(Race Condition)이 발생하여 메모리 누수나 객체의 조기 소멸 같은 심각한 오작동이 일어날 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GIL은 이러한 복잡한 동시성 문제를 객체 개별 단위로 잠금을 거는 대신, &lt;b&gt;인터프리터 전체에 하나의 거대한 락을 거는 단순한 방식&lt;/b&gt;으로 해결합니다. 이 방식은 인터프리터 구현을 매우 단순하게 만들며, 기존의 방대한 C 기반 확장 라이브러리(C 확장 모듈 등)와의 훌륭한 호환성을 유지할 수 있게 해줍니다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. GIL의 동작 방식 (멀티스레드 환경 실행 흐름)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GIL 체제 하에서 스레드는 파이썬 바이트코드를 실행하기 전에 반드시 GIL을 획득해야 하며, 주기적으로 다른 스레드에게 양보해야 합니다. 기본적으로 파이썬 3.12 기준, &lt;code&gt;sys.getswitchinterval()&lt;/code&gt;로 확인 가능한 &lt;b&gt;5ms(밀리초)&lt;/b&gt;마다 스레드 전환을 시도합니다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;!-- 두 번째 이미지 기반 구조화된 실행 흐름 --&gt;
&lt;div class=&quot;flowchart-container&quot;&gt;
&lt;div class=&quot;flowchart-title&quot;&gt;■ GIL 실행 흐름 상세 분석&lt;/div&gt;
&lt;div class=&quot;flow-grid&quot;&gt;
&lt;div class=&quot;flow-step&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;flow-step&quot;&gt;
&lt;div class=&quot;step-box&quot;&gt;
&lt;div class=&quot;step-desc&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-05-20 오후 4.21.34.png&quot; data-origin-width=&quot;1506&quot; data-origin-height=&quot;398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLCNqW/dJMcadotHpo/tYZzdkgMs0uLDuFvE9wVr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLCNqW/dJMcadotHpo/tYZzdkgMs0uLDuFvE9wVr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLCNqW/dJMcadotHpo/tYZzdkgMs0uLDuFvE9wVr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLCNqW%2FdJMcadotHpo%2FtYZzdkgMs0uLDuFvE9wVr1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1506&quot; height=&quot;398&quot; data-filename=&quot;스크린샷 2026-05-20 오후 4.21.34.png&quot; data-origin-width=&quot;1506&quot; data-origin-height=&quot;398&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;info-box&quot;&gt;&lt;b&gt;핵심 특징 요약:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GIL을 가진 스레드만 오직 Python bytecode를 실행할 수 있음.&lt;/li&gt;
&lt;li&gt;I/O 작업, &lt;code&gt;time.sleep()&lt;/code&gt;, 또는 GIL이 명시적으로 해제된 C 확장 함수(예: NumPy 연산) 내에서는 즉시 GIL을 반납함.&lt;/li&gt;
&lt;li&gt;정해진 시간 간격 후, 다른 스레드에게 GIL을 양보함으로써 멀티스레드 간의 최소한의 공정성을 유지함.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. GIL이 미치는 영향과 한계&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GIL은 멀티스레딩의 진정한 병렬 처리를 차단하므로, 멀티코어 환경에서도 &lt;b&gt;CPU 바운드 작업(CPU 연산이 많은 작업)&lt;/b&gt;의 성능을 크게 제한합니다. 여러 코어를 탑재한 최신 시스템일지라도 파이썬 멀티스레드는 결국 하나의 코어만을 시분할하여 교대로 사용하기 때문에 성능 이점이 전혀 없습니다.&lt;/p&gt;
&lt;div class=&quot;grid-layout&quot;&gt;
&lt;div class=&quot;grid-col grid-col-6 grid-col-padding-right&quot;&gt;
&lt;div style=&quot;font-weight: bold; font-size: 9.5pt; color: #1a365d; margin-bottom: 5px;&quot;&gt;# CPU 바운드 작업 예시 코드&lt;/div&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;import threading
import time

COUNT = 50000000

def cpu_task():
    total = 0
    for i in range(COUNT):
        total += i
    return total

def run_threads():
    start = time.time()
    t1 = threading.Thread(target=cpu_task)
    t2 = threading.Thread(target=cpu_task)
    t1.start(); t2.start()
    t1.join(); t2.join()
    print(f&quot;2 threads time: {time.time() - start:.2f}s&quot;)

def run_single():
    start = time.time()
    cpu_task()
    cpu_task()
    print(f&quot;2 tasks(single) time: {time.time() - start:.2f}s&quot;)

if __name__ == &quot;__main__&quot;:
    run_threads()
    run_single()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;grid-col grid-col-6 grid-col-padding-left&quot; style=&quot;padding-top: 25px;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #fafafa; border: 1px solid #e2e8f0; padding: 15px; border-radius: 4px; min-height: 200px;&quot;&gt;&lt;b&gt;실행 결과 예시 (4코어 CPU 환경)&lt;/b&gt;
&lt;ul style=&quot;padding-left: 18px; font-size: 9.5pt;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;2 threads time:&lt;/b&gt; 4.01s&lt;/li&gt;
&lt;li&gt;&lt;b&gt;2 tasks (single thread) time:&lt;/b&gt; 3.96s&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;font-size: 9.5pt; color: #4a5568; margin-top: 15px; border-top: 1px dashed #cbd5e1; padding-top: 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;분석 결과:&lt;/b&gt;&lt;br /&gt;두 개의 스레드로 나누어 병렬 실행을 기도했음에도 불구하고, 단일 스레드에서 순차적으로 두 번 실행한 것과 거의 동일하거나 오히려 약간 더 느린 시간이 걸립니다.&lt;br /&gt;&lt;span style=&quot;color: #2b4c7e; font-weight: bold;&quot;&gt;&amp;rarr; CPU 집중형 연산에서는 멀티스레딩의 이점이 전혀 존재하지 않음을 증명합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. Python 버전별 GIL 발전 및 해결 역사 (3.12, 3.13, 3.14 비교)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬 핵심 개발 커뮤니티는 오랜 기간 동안 GIL의 제약을 우회하거나 근본적으로 제거하기 위한 연구를 지속해 왔습니다. 최근 버전들에서의 주요 변화 요약은 다음과 같습니다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 15%;&quot;&gt;버전&lt;/th&gt;
&lt;th style=&quot;width: 15%;&quot;&gt;시기&lt;/th&gt;
&lt;th style=&quot;width: 30%;&quot;&gt;주요 내용&lt;/th&gt;
&lt;th style=&quot;width: 40%;&quot;&gt;설명 및 한계&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center; font-weight: bold;&quot;&gt;Python 3.12&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;2023.10&lt;/td&gt;
&lt;td&gt;기본 타임 슬라이싱 및 스레드 전환 로직 개선&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sys.setswitchinterval()&lt;/code&gt; 기본값 튜닝 및 스레드 간의 점유 공정성을 최적화하여 무의미하게 길어지는 GIL 독점을 축소했습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center; font-weight: bold;&quot;&gt;Python 3.13&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;2024.10&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Per-Interpreter GIL&lt;/b&gt; 도입 (선택적 사용)&lt;/td&gt;
&lt;td&gt;PEP 684 기반으로 설계되어, 한 프로세스 내에 독립된 메모리 공간을 갖는 여러 개의 서브 인터프리터를 생성해 &lt;b&gt;인터프리터별 독립 GIL&lt;/b&gt;을 부여함으로써 완벽한 병렬 처리를 부분적으로 지원합니다. (단, 객체 직접 공유는 불가능)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center; font-weight: bold;&quot;&gt;Python 3.14 (3.14.5)&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;2025.05&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Free-Threaded 빌드&lt;/b&gt; 제공 (GIL 제거 실험적 도입)&lt;/td&gt;
&lt;td&gt;PEP 703을 기반으로 하여 GIL을 완전히 제거할 수 있는 빌드 옵션(&lt;code&gt;--disable-gil&lt;/code&gt;)을 공식 제공합니다. 기존 레퍼런스 카운팅 메커니즘을 원자적(Atomic) 연산으로 대체하고 락 프리(Lock-free) 및 세분화된 락(Fine-grained lock) 전략을 채택하여 완전한 동시성을 검증 중에 있습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;추가적인 우회 및 대안 방법 (모든 버전 공통)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;multiprocessing 모듈 사용:&lt;/b&gt; 스레드 대신 완전히 별개의 OS 프로세스를 생성하므로, 각 프로세스가 개별 GIL을 지니게 되어 멀티코어를 완벽히 활용할 수 있습니다. (단, IPC 비용 발생)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;C/C++/Cython/NumPy 확장 모듈 사용:&lt;/b&gt; 내부 연산을 수행할 때 파이썬 인터프리터 단에서 GIL을 일시적으로 해제(Release)하고 진정한 멀티코어 연산을 끝낸 뒤 다시 복귀하는 방식입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;asyncio 모듈 활용:&lt;/b&gt; I/O 바운드 작업(네트워크 요청, 파일 읽기/쓰기 등)에 대해 싱글 스레드 내에서 코루틴 비동기 제어를 통해 작업 효율성을 최대화합니다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #f1f5f9; border-top: 3px solid #1a365d; padding: 12px 15px; margin-top: 20px; font-size: 10pt;&quot;&gt;&lt;b&gt;요약 및 결론:&lt;/b&gt;&lt;br /&gt;GIL은 과거 단일 코어 시절 파이썬의 개발 단순성과 실행 안정성을 보장해 준 든든한 버팀목이었으나, 멀티코어 시대에 들어서며 CPU 집약적 연산의 병렬 처리 병목 구간으로 지적받아 왔습니다. 파이썬 생태계는 이를 극복하기 위해 점진적으로 개선을 이뤄왔으며, 3.13의 서브 인터프리터 및 3.14의 Free-Threaded 빌드 도입을 기점으로 마침내 GIL 없는 진정한 고성능 병렬 프로그래밍 시대로 나아가고 있습니다.&lt;/div&gt;</description>
      <category>백엔드 엔지니어링(Backend Engineering)/Python 심화</category>
      <author>상원공원</author>
      <guid isPermaLink="true">https://infobox01219.tistory.com/1</guid>
      <comments>https://infobox01219.tistory.com/1#entry1comment</comments>
      <pubDate>Wed, 20 May 2026 17:11:32 +0900</pubDate>
    </item>
  </channel>
</rss>