01 · Punto de partida
El segundo rescata, el cuarto decora
Una caja con ρ = 1.8 vive en avalancha. Abrís la segunda y ρ cae a 0.9: la fila respira. Abrís la tercera y ρ cae a 0.6: vuela. Abrís la cuarta y casi no se nota: los tres ya daban abasto. Cada servidor extra rinde menos (Tema 22), pero el salto de 1 a 2 puede ser la diferencia entre colapso y calma.
Ese es el sistema M/M/c: c servidores idénticos en paralelo con fila única hacia el primero libre. Paralelismo da capacidad, reparto la aprovecha, escala decide cuántos pagar.
- ¿Cuántos servidores hacen falta para ρ < 1 y para Wq aceptable?
- ¿Fila única o una fila por servidor?
- ¿Cuánto mejora cada servidor extra y cuándo frenar?
- ¿Cómo predigo Wq con c > 1 sin simular?
02 · Definición
Paralelismo, reparto y escala
Paralelismo
c servidores idénticos atienden a la vez. Capacidad cμ; estado = nº ocupados (0…c) + cola.
Reparto
Fila única hacia el primero libre. Sin decisiones por cliente: el hueco manda. (Filas separadas = Tema 22.)
Escala
Cada c extra baja Wq con retornos decrecientes. Dimensionar es parar donde el ahorro paga el salario.
| c | ρ = λ/cμ | Régimen | Wq M/M/c |
|---|---|---|---|
| 1 | 1.80 | Avalancha | ∞ (no estabiliza) |
| 2 | 0.90 | Tenso | ≈ 8 min (rescate) |
| 3 | 0.60 | Ágil | ≈ 0.9 min (pulido) |
| 4 | 0.45 | Sobra | ≈ 0.2 min (lujo) |
03 · El corazón: pooling
Fila única que aprovecha huecos
Con filas separadas, un cliente queda clavado en su fila mientras otra caja se libera (el supermercado clásico). Con fila única, cada liberación toma al primero de la cola: ningún servidor descansa habiendo espera. Esa ganancia se llama pooling: el mismo c rinde más unido que partido. Erlang C la cuantifica: es la probabilidad de esperar C(c,a), que cae fuerte con cada c extra hasta aplanarse.
- 1Estimar λ y μ.
Como en c=1. La oferta es a = λ/μ (erlangs): los servidores “ocupados equivalentes”.
- 2Probar c con ρ.
ρ = a/c < 1 es el piso: c mínimo = ⌈a⌉ + 1 en la práctica (con ⌈a⌉ apenas respira).
- 3Predecir con Erlang C.
Wq = C(c,a)/(cμ − λ). Un renglón para comparar c = 2, 3, 4 (bloque Python).
- 4Validar con fila única.
Simular con
libre_en[c]y asignar al mínimo: si difiere de Erlang C, el reparto está mal.
- Erlang C
- P(esperar) en M/M/c: C(c,a) = [ac/(c!(1−ρ))] / [Σk<c ak/k! + ac/(c!(1−ρ))]. Con ella, Lq = C·ρ/(1−ρ).
- Pooling
- Unir capacidad y cola: c juntos esperan menos que c separados con la misma λ repartida. El lab lo muestra bajando Wq a igual ρ.
- Retornos decrecientes
- El 2º parte la espera, el 5º la roza. Dimensionar es frenar donde ΔWq ya no paga el servidor.
- Heterogéneos
- Si difieren (caja rápida/lenta), el estado ya no es un contador: importa cuál está libre y la regla de asignación (Tema 22).
Filas separadas
Huecos desperdiciados
Cada fila es un M/M/1 chico con λ/c. Un servidor ocioso no ayuda a la fila vecina: espera mayor a igual c.
Fila única (pooling)
Cada hueco rinde
Un M/M/c con la λ total. Menor Wq, menor varianza y justicia FIFO global. El cartel “pase al primero libre” es pooling.
04 · Ejemplos
Cuatro c que conocés
- 1Banco 2 cajas, fila única.
El cartel “avance al primero libre” es Erlang C en la pared: dos rinden casi como una doble de rápida.
- 2Call center 8 agentes.
a = 6 erlangs ⇒ ρ = 0.75. Erlang C dimensiona para “80% atendido en 20 s”.
- 3Peaje 4 cabinas.
En pico abre la 4ª: ρ baja de 0.95 a 0.7 y la cola deja la ruta.
- 4Web 8 workers.
Requests a memoria compartida: pooling perfecto, sin costo de reparto visible.
05 · Representación en Python
Erlang C en un renglón, reparto en tres
La teoría predice con factoriales; la simulación reparte con min(libre_en). Ambas con fila única.
Python en tu navegador. El primero compara c = 1…4 con Erlang C; el segundo simula el reparto y valida. Cambiá c y mirá el rescate.
# Erlang C y Wq M/M/c: lam=0.9/min, S=2 (mu=0.5)
import math
lam, mu = 0.9, 0.5
a = lam / mu
for c in [1, 2, 3, 4]:
rho = a / c
if rho >= 1:
print(f"c={c} rho={rho:.2f} avalancha"); continue
s = sum(a**k / math.factorial(k) for k in range(c))
C = (a**c / (math.factorial(c) * (1 - rho))) / (s + a**c / (math.factorial(c) * (1 - rho)))
print(f"c={c} rho={rho:.2f} P(espera)={C:.2f} Wq={C/(c*mu-lam):.2f}")
# Reparto fila única: Poisson + Exp, c=2, T=200
import random
random.seed(29)
lam, mu, c, T = 0.9, 0.5, 2, 200.0
t, libres, wqs = 0.0, [0.0]*c, []
while t < T:
t += random.expovariate(lam)
k = min(range(c), key=lambda j: libres[j])
ini = max(t, libres[k])
libres[k] = ini + random.expovariate(mu)
wqs.append(ini - t)
print(f"Wq sim={sum(wqs)/len(wqs):.2f} (teoría ~8 con c=2)")
06 · Exploración
Laboratorio: sumar c, domar ρ
Simulamos M/M/c con fila única hasta T = 60 (semilla fija). La escalera es N(t); la línea punteada es c (si N > c, hay cola). Subí c con λ y S fijos: verás la escalera dejar de vivir arriba de c y la Wq derretirse — con retornos decrecientes.
Pooling: cada servidor extra rinde menos
ρ = λS/c · Wq = C(c,a)/(cμ−λ)
Sumá c para domar la cola.
Escalera lima = N(t); punteada blanca = c. Por encima de c hay cola; por debajo sobran manos. La Wq teórica usa Erlang C.
Preguntas para explorar
- Con λ=0.5, S=2: ¿Wq con c=1 (ρ=1.0) vs c=2 (ρ=0.5)? ¿Qué hizo el segundo?
- Con c=2 y λ=0.75, S=2 (ρ=0.75): ¿% que espera? ¿Y con c=3 (ρ=0.5)?
- De c=3 a c=4 con ρ ya baja: ¿cuánto baja Wq? ¿Pagarías ese servidor?
Ver respuestas sugeridas
- c=1 avalancha (sin teoría); c=2 Wq ≈ 1: el segundo rescata del colapso a la calma.
- c=2 espera ~50–60%; c=3 ~25–35%: el tercero pule. (Valores sim con T=60 ± ruido.)
- Apenas décimas: pooling ya rindió. Solo se paga si el SLA lo exige o el pico crece.
07 · Comprensión
Confusiones frecuentes
«Doble de servidores, mitad de espera»
No es lineal: de avalancha a calma el salto es gigante; en régimen el 4º apenas mueve Wq. Se dimensiona por curva, no por regla de tres.
«Una fila por servidor es lo mismo»
Es c veces M/M/1 con λ/c: siempre espera más que el M/M/c unido. Fila única o pooling perdido.
«ρ = 0.9 con c=3 es igual que con c=1»
ρ igual, espera distinta: a igual ρ, más c ⇒ menos Wq (más manos absorben rachas). Erlang C lo cuantifica.
«Servidores distintos se promedian»
Promediar μ rápida+lenta inventa un cμ falso: el reparto importa (la lenta frena). Se modelan uno por uno.
08 · Práctica guiada
Ejercicios con Python
Ejercicio 1: mínimo para estabilizar
λ=0.9/min, S=2. ¿c mínimo con ρ < 1? ¿ρ con ese c?
lam, S = 0.9, 2.0
a = lam * S
c = int(a) + 1
print(f"a={a} c_min={c} rho={a/c:.2f}") # a=1.8 c=2 rho=0.90
Ver solución razonada
a = 1.8 erlangs ⇒ c = 2 (ρ=0.9, tenso) y c = 3 lo deja en 0.6 (ágil). El mínimo estabiliza; el siguiente humaniza.
Ejercicio 2: leer Erlang C
Con el bloque Python, ¿P(espera) con c=2 y c=3 para λ=0.9, μ=0.5?
# Reutilizá el bloque de Erlang C: con c=2 da ~0.85, con c=3 ~0.35
print("c=2 espera la mayoría; c=3 espera uno de cada tres")
Ver solución
C(2,1.8) ≈ 0.85 y C(3,1.8) ≈ 0.35: el tercer servidor parte la probabilidad de esperar, no solo la media.
Ejercicio 3: fila única vs separadas
λ=0.9 total en 2 filas separadas (0.45 cada una, c=1). ¿ρ y Wq por fila vs M/M/2?
Ver una posible respuesta
lam, mu = 0.45, 0.5
print(f"separadas: rho={lam/mu:.2f} Wq={lam/(mu*(mu-lam)):.1f} vs M/M/2 Wq~8x menos")
Separadas: ρ=0.9, Wq≈18 por fila; unidas M/M/2: Wq≈8 total. Mismo personal, pooling mediante.
09 · Síntesis
Ideas para recordar
- c en paralelo + fila única: ρ = λ/(cμ), capacidad cμ.
- Erlang C da P(espera) y Wq: el 2º rescata, el 4º decora.
- Pooling: unir rinde más que partir (M/M/c vs c×M/M/1).
- En Python:
libre_en[c]al mínimo; teoría con factoriales. - A igual ρ, más c espera menos: dimensionar por Wq, no solo por ρ.
En el próximo tema pondremos nombre a todo esto: la notación de Kendall.