Hoppa till innehållet
AI-grafen
E· Universitetinferens-optimering· ca 60 min· utvecklande· verifierad 2026-09-20

Latens, throughput och batching vid inferens

Kunna mäta och resonera om latens kontra throughput och kontinuerlig batching.

Förkunskaper

Intuition

Tre tal som ofta blandas ihop:

MåttVadVem bryr sig
TTFT (time to first token)hur snabbt något börjar händaanvändaren — det här känns som «snabbhet»
TPOT (tid per token)hur snabbt texten rullar utanvändaren, vid långa svar
Throughputtokens per sekund totalt över alla användareden som betalar hårdvaran

De står i konflikt. Större batch → högre throughput, sämre TTFT för den enskilde. Du måste välja vilket krav som styr — och mäta båda.

En tumregel som håller: TTFT under 1 s och 20+ tokens/s upplevs som snabbt i chatt. Under 10 tokens/s känns det trögt även om svaret är bra.

Formellt

Statisk batching väntar in N förfrågningar, kör dem tillsammans och släpper alla när den längsta är klar. En förfrågan som genererar 20 tokens väntar på en som genererar 800. Utnyttjandegraden blir usel.

Continuous batching (Orca, vLLM) arbetar på iterationsnivå: efter varje avkodningssteg släpps färdiga sekvenser ut och nya tas in i deras plats. Effekten är 2–10× högre throughput vid samma latenskrav — den enskilt största vinsten i en LLM-tjänst.

Köteori räcker för att sätta förväntningar: med ankomstintensitet λ och servicekapacitet μ växer väntetiden mot oändligheten när utnyttjandegraden ρ = λ/μ närmar sig 1. Planera för ρ ≈ 0,6–0,7 vid p95-krav; kör du på 0,95 har du ingen marginal för trafiktoppar.

Mätprotokoll som ger jämförbara tal: fast promptlängd och fast antal genererade tokens, uppvärmning före mätning, median och p95 (inte medelvärde), och belastning från flera samtidiga klienter — annars mäter du bara enanvändarfallet.

Kod

import asyncio, time, numpy as np

async def en_forfragan(klient, prompt, max_tokens=128):
    t0 = time.perf_counter(); forsta = None; n = 0
    async for _tok in klient.stream(prompt, max_tokens=max_tokens):
        if forsta is None:
            forsta = time.perf_counter() - t0
        n += 1
    total = time.perf_counter() - t0
    return {"ttft": forsta, "tpot": (total - forsta) / max(n - 1, 1), "total": total, "tokens": n}

async def belastningstest(klient, prompt, samtidiga=16, per_klient=5):
    t0 = time.perf_counter()
    res = await asyncio.gather(*[en_forfragan(klient, prompt)
                                 for _ in range(samtidiga * per_klient)])
    vagg = time.perf_counter() - t0
    ttft = np.array([r["ttft"] for r in res]); tpot = np.array([r["tpot"] for r in res])
    return {"samtidiga": samtidiga,
            "ttft_p50_ms": round(np.percentile(ttft, 50) * 1000),
            "ttft_p95_ms": round(np.percentile(ttft, 95) * 1000),
            "tokens_per_s_per_anv": round(1 / np.median(tpot), 1),
            "throughput_tokens_per_s": round(sum(r["tokens"] for r in res) / vagg)}

# samtidiga=1:  ttft_p50 180 ms, 45 tok/s/anv, throughput 45
# samtidiga=16: ttft_p50 520 ms, 28 tok/s/anv, throughput 448   ← 10× throughput, 3× TTFT

Behärskning innebär

  • Mäter TTFT, tid per token och throughput separat
  • Förklarar continuous batching
  • Väljer batchstrategi efter krav

Logga in för att göra övningarna och bygga upp din behärskning.

Källor

Alla källor och licenser