Skip to content

Commit 8a179a9

Browse files
committed
dat
1 parent 2f2f829 commit 8a179a9

File tree

1 file changed

+124
-56
lines changed

1 file changed

+124
-56
lines changed

readme.md

Lines changed: 124 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,158 @@
1+
# Benchmark: .NET vs. Node.js vs. Bun para Procesamiento Intensivo
12

3+
Este documento detalla una serie de benchmarks realizados para comparar el rendimiento de C# (.NET), Bun y Node.js en una tarea de procesamiento de datos intensiva ("mastica-historial").
24

5+
## Fase 1: Benchmark Inicial (Versión no optimizada)
36

4-
PS C:\Users\frtri\Documents\benchmarksMiiot\miiot-benchmarks> bun run .\bun-mastica-historial\benchmark.js
7+
Las primeras pruebas se realizaron con una implementación directa del algoritmo.
8+
9+
### Bun JS (no optimizado)
10+
11+
```powershell
12+
PS C:\...\miiot-benchmarks> bun run .\bun-mastica-historial\benchmark.js
513
Bun JS - Tiempo: 11.53 s
614
Buckets calculados: 5000001
7-
PS C:\Users\frtri\Documents\benchmarksMiiot\miiot-benchmarks> bun run .\bun-mastica-historial\benchmark.js
15+
16+
PS C:\...\miiot-benchmarks> bun run .\bun-mastica-historial\benchmark.js
817
Bun JS - Tiempo: 13.76 s
918
Buckets calculados: 5000001
10-
PS C:\Users\frtri\Documents\benchmarksMiiot\miiot-benchmarks> dotnet run --project .\dotnet-mastica-historial\dotnet-mastica-historial.csproj
11-
C# .NET - Tiempo: 7,123 s
12-
Buckets calculados: 5000000
13-
PS C:\Users\frtri\Documents\benchmarksMiiot\miiot-benchmarks> bun run .\bun-mastica-historial\benchmark.js
19+
20+
PS C:\...\miiot-benchmarks> bun run .\bun-mastica-historial\benchmark.js
1421
Bun JS - Tiempo: 11.40 s
1522
Buckets calculados: 5000001
23+
```
24+
25+
### C# .NET (no optimizado)
26+
27+
```powershell
28+
PS C:\...\miiot-benchmarks> dotnet run --project .\dotnet-mastica-historial\dotnet-mastica-historial.csproj
29+
C# .NET - Tiempo: 7,123 s
30+
Buckets calculados: 5000000
31+
```
32+
33+
---
34+
35+
## Fase 2: Benchmark Optimizado
1636

37+
> **NOTA:** Se realizó una optimización del código para evitar problemas de alto consumo de memoria que provocaban que el Garbage Collector de .NET terminara el proceso prematuramente.
1738
18-
OPTIMIZADO POR QUE NO CABE EN LA MEMORIA Y LO CORTABA EL GARBACE COLLECTOR DE .NET
39+
### Bun/Node JS (Optimizado)
1940

20-
PS C:\Users\frtri\Documents\benchmarksMiiot\miiot-benchmarks> bun run .\bun-mastica-historial\benchmark.js
41+
```powershell
42+
PS C:\...\miiot-benchmarks> bun run .\bun-mastica-historial\benchmark.js
2143
Iniciando benchmark optimizado de Node.js/Bun...
2244
Bun/Node JS (Optimizado) - Tiempo: 8.083 s
2345
Buckets calculados: 5000001
24-
PS C:\Users\frtri\Documents\benchmarksMiiot\miiot-benchmarks> dotnet run --project .\dotnet-mastica-historial\dotnet-mastica-historial.csproj
25-
C# .NET (Optimizado) - Tiempo: 2,168 s
26-
Buckets calculados: 5000001
27-
PS C:\Users\frtri\Documents\benchmarksMiiot\miiot-benchmarks> node .\bun-mastica-historial\benchmark.js
46+
47+
PS C:\...\miiot-benchmarks> node .\bun-mastica-historial\benchmark.js
2848
Iniciando benchmark optimizado de Node.js/Bun...
2949
Bun/Node JS (Optimizado) - Tiempo: 19.884 s
3050
Buckets calculados: 5000001
51+
```
3152

32-
![Resultados del benchmark](benchmark-result.png)
53+
### C# .NET (Optimizado)
3354

55+
```powershell
56+
PS C:\...\miiot-benchmarks> dotnet run --project .\dotnet-mastica-historial\dotnet-mastica-historial.csproj
57+
C# .NET (Optimizado) - Tiempo: 2,168 s
58+
Buckets calculados: 5000001
59+
```
3460

35-
(1 core bun vs 8 core .net)
61+
---
3662

37-
asi se compila en modo release no debug, ya que ne debug tarda mas
38-
PS C:\Users\frtri\Documents\benchmarksMiiot\miiot-benchmarks> dotnet run --project .\dotnet-mastica-historial\dotnet-mastica-historial.csproj
63+
## Fase 3: Máxima Optimización (Modo Release y AOT-like)
64+
65+
Para obtener los resultados más precisos, se compiló el proyecto de .NET en modo **Release** y se utilizó un script específico para JS que parece aplicar optimizaciones previas (similar a AOT).
66+
67+
### C# .NET (Modo Release)
68+
69+
Ejecución en modo Debug (referencia):
70+
```powershell
71+
PS C:\...\miiot-benchmarks> dotnet run --project .\dotnet-mastica-historial\dotnet-mastica-historial.csproj
3972
C# .NET (Optimizado) - Tiempo: 2,249 s
4073
Buckets calculados: 5000001
74+
```
4175

42-
MODO RELEASE.
43-
44-
dotnet run -c Release --project .\dotnet-mastica-historial\dotnet-mastica-historial.csproj
45-
PS C:\Users\frtri\Documents\benchmarksMiiot\miiot-benchmarks> dotnet run -c Release --project .\dotnet-mastica-historial\dotnet-mastica-historial.csproj
76+
Ejecución en modo **Release** (más rápido):
77+
```powershell
78+
PS C:\...\miiot-benchmarks> dotnet run -c Release --project .\dotnet-mastica-historial\dotnet-mastica-historial.csproj
4679
C# .NET (Optimizado) - Tiempo: 1,540 s
4780
Buckets calculados: 5000001
81+
```
82+
83+
### Bun/Node.js (Procesamiento AOT-like)
4884

49-
PS C:\Users\frtri\Documents\benchmarksMiiot\miiot-benchmarks> bun .\bun-mastica-historial\aot-processing.js
85+
```powershell
86+
PS C:\...\miiot-benchmarks> bun .\bun-mastica-historial\aot-processing.js
5087
Node.js - Tiempo: 1.482 s
5188
Buckets calculados: 5000001
52-
PS C:\Users\frtri\Documents\benchmarksMiiot\miiot-benchmarks> node .\bun-mastica-historial\aot-processing.js
89+
90+
PS C:\...\miiot-benchmarks> node .\bun-mastica-historial\aot-processing.js
5391
Node.js - Tiempo: 4.407 s
5492
Buckets calculados: 5000001
93+
```
94+
95+
---
96+
97+
## Resumen de Resultados (Mejores Tiempos)
98+
99+
| Runtime | Tiempo (s) | Observaciones |
100+
| :--- | :--- | :--- |
101+
| **Bun** | **1.482 s** | 🥇 **El ganador**. Sorprendentemente, supera a todos en esta prueba. |
102+
| **.NET (Release)** | **1.540 s** | 🥈 Prácticamente un empate técnico con Bun. Un rendimiento excepcional. |
103+
| **Node.js** | **4.407 s** | 🐢 El más lento en esta tarea de cómputo. Casi 3x más lento que Bun/.NET. |
104+
| **.NET (Debug)** | **2.249 s** | Significativamente más lento que en modo Release, como era de esperar. |
105+
106+
![Resultados del benchmark](benchmark-result.png)
107+
108+
### ⚠️ Aclaración Importante sobre los Cores
109+
> **Nota del autor original:** La comparativa se realizó con **Bun usando 1 core vs .NET usando 8 cores**.
110+
111+
Este es un detalle crítico que sugiere que el algoritmo en .NET no estaba paralelizado para aprovechar los 8 cores, o que el rendimiento de Bun en un solo núcleo es excepcionalmente alto para esta tarea específica.
112+
113+
---
114+
115+
## Análisis Detallado y Preguntas Frecuentes (Q&A)
116+
117+
> **Pregunta: "¿No has hecho trampas optimizando más Node no?"**
118+
119+
¡Absolutamente no! Y me alegra que lo preguntes, porque es la clave de una buena comparativa. El código de Node.js es una réplica directa y fiel de la lógica del código de C#.
55120

56-
"¿No has hecho trampas optimizando más Node no?"
57-
¡Absolutamente no! Y me alegra que lo preguntes, porque es la clave de una buena comparativa. El código de Node.js que te proporcioné es una réplica directa y fiel de la lógica del código de C#.
58121
Vamos a comprobarlo pieza por pieza:
59-
Lógica C# Lógica Node.js ¿Es equivalente?
60-
for (int i = 0; i < n; i++) for (let i = 0; i < n; i++) Sí, bucle idéntico.
61-
DateTime + TimeSpan Date + milisegundos Sí, ambos manejan el tiempo. JS usa números (ms) que es incluso más directo.
62-
rnd.NextDouble() * 100 Math.random() * 100 Sí, ambos generan un número aleatorio entre 0 y 100.
63-
(long)(ts.Ticks / interval.Ticks) Math.floor(ts_ms / interval_ms) Sí, es la misma operación matemática para agrupar en "buckets".
64-
Dictionary<long, (sum, count)> Map<number, {sum, count}> Sí, Map es el equivalente de alto rendimiento a Dictionary.
65-
.Select(g => g.sum / g.count) .map(g => g.sum / g.count) Sí, es la misma transformación para calcular el promedio final.
66-
Conclusión: La comparación es justa. El algoritmo es el mismo. Lo que estamos midiendo aquí es la pura eficiencia del runtime (.NET, Node.js, Bun) para ejecutar este algoritmo específico.
67-
Análisis de los Resultados
68-
Aquí es donde se pone emocionante. Vamos a ordenar tus resultados de más rápido a más lento:
69-
Runtime Tiempo (s) Observaciones
70-
Bun 1.482 s 🥇 El ganador. Sorprendentemente, supera a todos.
71-
.NET (Release) 1.540 s 🥈 Prácticamente un empate técnico con Bun. Una diferencia de ~3% es mínima y puede ser ruido de la ejecución. Un rendimiento excepcional.
72-
.NET (Debug) 2.249 s Rendimiento sin optimizaciones. Como esperábamos, es significativamente más lento que en modo Release.
73-
Node.js 4.407 s 🐢 El más lento (en este caso). Casi 3 veces más lento que Bun y .NET.
74-
¿Qué está pasando aquí? ¿Por qué estos resultados?
75-
Bun vs. Node.js (La gran sorpresa):
76-
Motor JavaScript Diferente: Node.js usa el motor V8 (de Google Chrome). Bun usa JavaScriptCore (JSC) (de Apple Safari). Para esta tarea específica de un bucle "caliente" (hot loop) con muchas operaciones matemáticas y de acceso a objetos, el compilador JIT de JSC está demostrando ser drásticamente más eficiente que el JIT de V8.
77-
Enfoque en el rendimiento: Bun fue construido desde cero con el rendimiento como objetivo principal, y estos resultados lo demuestran. Su implementación de Map, Math y el manejo del bucle está, para este caso, mucho más optimizada.
78-
.NET (Release) - El campeón tradicional:
79-
.NET sigue siendo un monstruo del rendimiento para tareas de cómputo intensivo (CPU-bound). El compilador RyuJIT en modo Release hace un trabajo increíble optimizando el código.
80-
El hecho de que esté casi empatado con Bun demuestra lo maduro y optimizado que está el runtime de .NET. Para ser un ecosistema mucho más antiguo, mantenerse a la par con el "chico nuevo y rápido" es un logro enorme.
81-
Node.js (V8) - ¿Por qué se queda atrás en esta prueba?
82-
No significa que Node.js sea lento. Node.js es increíblemente rápido para su principal caso de uso: operaciones de I/O (Entrada/Salida) asíncronas (servidores web, APIs, acceso a bases de datos, etc.).
83-
Este benchmark es 100% CPU-bound. Es un bucle numérico que no espera por nada. Este es precisamente el tipo de escenario donde las debilidades relativas del JIT de V8 (comparado con .NET o JSC en este caso) se hacen más evidentes.
84-
El motor V8 puede haber tomado una ruta de optimización diferente o menos eficiente para este patrón de código específico. Pequeñas diferencias en cómo se manejan los objetos, los números de punto flotante o los accesos al Map pueden acumularse en 50 millones de iteraciones.
85-
Conclusiones Finales
86-
Has confirmado la importancia del modo Release: La diferencia entre .NET Debug (2.24s) y Release (1.54s) es enorme. ¡Nunca midas rendimiento en modo Debug!
87-
Bun es un competidor muy serio: Para tareas de procesamiento y cómputo, Bun no es solo marketing. Es realmente, realmente rápido.
88-
.NET sigue siendo una potencia: Ofrece un rendimiento de primer nivel, robustez y un ecosistema maduro. Sigue siendo una de las mejores opciones para backends de alto rendimiento.
89-
Elige la herramienta adecuada para el trabajo: Si tu aplicación es principalmente un servidor API que maneja muchas peticiones concurrentes (I/O-bound), Node.js sigue siendo una opción fantástica. Si una parte crítica de tu aplicación es un algoritmo de procesamiento de datos intensivo como este, .NET o Bun podrían darte un rendimiento significativamente mejor.
90-
¡Una comparación excelente y con resultados muy reveladores
122+
123+
| Lógica C# | Lógica Node.js | ¿Es equivalente? |
124+
| :--- | :--- | :--- |
125+
| `for (int i = 0; i < n; i++)` | `for (let i = 0; i < n; i++)` | ****, bucle idéntico. |
126+
| `DateTime + TimeSpan` | `Date + milisegundos` | ****, ambos manejan el tiempo. JS usa números (ms) que es incluso más directo. |
127+
| `rnd.NextDouble() * 100` | `Math.random() * 100` | ****, ambos generan un número aleatorio entre 0 y 100. |
128+
| `(long)(ts.Ticks / interval.Ticks)` | `Math.floor(ts_ms / interval_ms)` | ****, es la misma operación matemática para agrupar en "buckets". |
129+
| `Dictionary<long, (sum, count)>` | `Map<number, {sum, count}>` | ****, `Map` es el equivalente de alto rendimiento a `Dictionary`. |
130+
| `.Select(g => g.sum / g.count)` | `.map(g => g.sum / g.count)` | ****, es la misma transformación para calcular el promedio final. |
131+
132+
**Conclusión:** La comparación es justa. El algoritmo es el mismo. Lo que estamos midiendo aquí es la pura eficiencia del runtime (.NET, Node.js, Bun) para ejecutar este algoritmo específico.
133+
134+
### Análisis de los Resultados
135+
136+
Aquí es donde se pone emocionante.
137+
138+
* **Bun vs. Node.js (La gran sorpresa):**
139+
* **Motor JavaScript Diferente:** Node.js usa el motor V8 (de Google Chrome). Bun usa JavaScriptCore (JSC) (de Apple Safari). Para esta tarea específica de un bucle "caliente" (hot loop) con muchas operaciones matemáticas y de acceso a objetos, el compilador JIT de JSC está demostrando ser drásticamente más eficiente que el JIT de V8.
140+
* **Enfoque en el rendimiento:** Bun fue construido desde cero con el rendimiento como objetivo principal, y estos resultados lo demuestran. Su implementación de `Map`, `Math` y el manejo del bucle está, para este caso, mucho más optimizada.
141+
142+
* **.NET (Release) - El campeón tradicional:**
143+
* .NET sigue siendo un monstruo del rendimiento para tareas de cómputo intensivo (CPU-bound). El compilador RyuJIT en modo Release hace un trabajo increíble optimizando el código.
144+
* El hecho de que esté casi empatado con Bun demuestra lo maduro y optimizado que está el runtime de .NET. Para ser un ecosistema mucho más antiguo, mantenerse a la par con el "chico nuevo y rápido" es un logro enorme.
145+
146+
* **Node.js (V8) - ¿Por qué se queda atrás en esta prueba?**
147+
* No significa que Node.js sea lento. Node.js es increíblemente rápido para su principal caso de uso: operaciones de I/O (Entrada/Salida) asíncronas (servidores web, APIs, acceso a bases de datos, etc.).
148+
* Este benchmark es **100% CPU-bound**. Es un bucle numérico que no espera por nada. Este es precisamente el tipo de escenario donde las debilidades relativas del JIT de V8 (comparado con .NET o JSC en este caso) se hacen más evidentes.
149+
* El motor V8 puede haber tomado una ruta de optimización diferente o menos eficiente para este patrón de código específico. Pequeñas diferencias en cómo se manejan los objetos, los números de punto flotante o los accesos al `Map` pueden acumularse en 50 millones de iteraciones.
150+
151+
---
152+
153+
## Conclusiones Finales
154+
155+
* **Has confirmado la importancia del modo Release:** La diferencia entre .NET Debug (2.24s) y Release (1.54s) es enorme. ¡Nunca midas rendimiento en modo Debug!
156+
* **Bun es un competidor muy serio:** Para tareas de procesamiento y cómputo, Bun no es solo marketing. Es realmente, realmente rápido.
157+
* **.NET sigue siendo una potencia:** Ofrece un rendimiento de primer nivel, robustez y un ecosistema maduro. Sigue siendo una de las mejores opciones para backends de alto rendimiento.
158+
* **Elige la herramienta adecuada para el trabajo:** Si tu aplicación es principalmente un servidor API que maneja muchas peticiones concurrentes (I/O-bound), Node.js sigue siendo una opción fantástica. Si una parte crítica de tu aplicación es un algoritmo de procesamiento de datos intensivo como este, .NET o Bun podrían darte un rendimiento significativamente mejor.

0 commit comments

Comments
 (0)