Sofortantwort
Latency vs. Throughput einfach erklärt
Latenz = wie schnell eine Anfrage. Throughput = wie viele Anfragen pro Zeit.
- Kurz gesagt
- Latenz: Zeit für eine einzelne Operation (ms)
- Typischer Einsatz
- Real-Time APIs, Batch Processing, ML Inference
- Wichtig zu wissen
- Oft Trade-off: Batching erhöht Throughput, aber auch Latenz
Latency vs. Throughput im Überblick
Latenz und Throughput sind zwei zentrale Performance-Metriken. Sie messen verschiedene Dinge und stehen je nach Architektur, Last und Optimierung oft in einem Trade-off.
Die Definitionen:
Latenz (Latency):
"Wie lange dauert EINE Anfrage?"
→ Gemessen in Millisekunden (ms)
→ Wichtig für User Experience
Throughput:
"Wie viele Anfragen pro Sekunde?"
→ Gemessen in Requests/Second (RPS)
→ Wichtig für Kapazität
Beispiel:
| System | Latenz | Throughput | Use Case |
|---|---|---|---|
| Chat-API | niedriger Zielwert | moderater Durchsatz | Interaktiv |
| Batch-ML | höher tolerierbar | hoher Durchsatz | Hintergrund |
| Datenbank | workloadabhängig | workloadabhängig | Beides wichtig |
Technisch betrachtet
Der Trade-off
Ohne Batching:
Request 1: ──────► einzelne Verarbeitung
Request 2: ──────► einzelne Verarbeitung
Request 3: ──────► einzelne Verarbeitung
Latenz: niedriger, Throughput: begrenzt durch Overhead
Mit Batching:
Request 1: ─┐
Request 2: ─┼─────────► gemeinsame Verarbeitung
Request 3: ─┘
Latenz: kann steigen, Throughput kann steigen
Latenz-Metriken
import numpy as np
def analyze_latencies(latencies):
return {
"p50": np.percentile(latencies, 50), # Median
"p90": np.percentile(latencies, 90), # 90% schneller
"p95": np.percentile(latencies, 95), # 95% schneller
"p99": np.percentile(latencies, 99), # 99% schneller
"p999": np.percentile(latencies, 99.9), # Worst case
"mean": np.mean(latencies),
"max": np.max(latencies),
}
# Beispiel
latencies = observed_latencies_ms
# Percentiles zeigen Tail-Latency oft besser als der Durchschnitt
Throughput messen
import time
import asyncio
async def benchmark_throughput(client, duration_seconds):
start = time.time()
request_count = 0
while time.time() - start < duration_seconds:
await client.request()
request_count += 1
elapsed = time.time() - start
throughput = request_count / elapsed
return f"{throughput:.2f} requests/second"
Little’s Law
L = λ × W
L = Anzahl gleichzeitiger Requests im System
λ = Throughput (Requests/Sekunde)
W = Durchschnittliche Latenz (Sekunden)
Beispiel:
- Throughput: λ Requests/Sekunde
- Latenz: W Sekunden
- Gleichzeitige Requests: L = λ × W
Optimierungsstrategien
| Ziel | Strategie |
|---|---|
| Niedrige Latenz | Caching, Edge Computing, weniger Hops prüfen |
| Hoher Throughput | Batching, Parallelisierung, Async prüfen |
| Beides | Horizontale Skalierung, effiziente Implementierung und Kapazitätsplanung |
ML-Inference Beispiel
# Ohne Batching: oft niedrigere Latenz, aber begrenzter Throughput
async def predict_single(model, input):
return model(input)
# Mit Batching: potenziell höhere Latenz, aber höherer Throughput
class BatchPredictor:
def __init__(self, model, batch_size, max_wait_ms):
self.model = model
self.batch_size = batch_size
self.max_wait = max_wait_ms / 1000
self.queue = []
async def predict(self, input):
future = asyncio.Future()
self.queue.append((input, future))
if len(self.queue) >= self.batch_size:
await self._process_batch()
else:
await asyncio.sleep(self.max_wait)
if self.queue:
await self._process_batch()
return await future
async def _process_batch(self):
batch = self.queue[:self.batch_size]
self.queue = self.queue[self.batch_size:]
inputs = [item[0] for item in batch]
results = self.model(inputs) # Batch inference
for (_, future), result in zip(batch, results):
future.set_result(result)