Searching...
Español
EnglishEnglish
EspañolSpanish
简体中文Chinese
FrançaisFrench
DeutschGerman
日本語Japanese
PortuguêsPortuguese
ItalianoItalian
한국어Korean
РусскийRussian
NederlandsDutch
العربيةArabic
PolskiPolish
हिन्दीHindi
Tiếng ViệtVietnamese
SvenskaSwedish
ΕλληνικάGreek
TürkçeTurkish
ไทยThai
ČeštinaCzech
RomânăRomanian
MagyarHungarian
УкраїнськаUkrainian
Bahasa IndonesiaIndonesian
DanskDanish
SuomiFinnish
БългарскиBulgarian
עבריתHebrew
NorskNorwegian
HrvatskiCroatian
CatalàCatalan
SlovenčinaSlovak
LietuviųLithuanian
SlovenščinaSlovenian
СрпскиSerbian
EestiEstonian
LatviešuLatvian
فارسیPersian
മലയാളംMalayalam
தமிழ்Tamil
اردوUrdu
Writing High-Performance .NET Code

Writing High-Performance .NET Code

por Ben Watson 2014 280 páginas
4.31
290 calificaciones
Escuchar
Try Full Access for 7 Days
Unlock listening & more!
Continue

Puntos clave

1. Mide Todo: El Rendimiento se Basa en Datos.

No conocerás dónde están tus problemas de rendimiento si no has medido con precisión.

El rendimiento no es cuestión de suposiciones. Las corazonadas y la inspección del código pueden dar pistas, pero solo una medición exacta revela los verdaderos cuellos de botella. Optimizar prematuramente código no crítico es una pérdida de tiempo; enfoca tus esfuerzos donde el impacto sea mayor, guiado por datos.

Define metas cuantificables. Conceptos vagos como "rápido" o "responsivo" no sirven; los requisitos de rendimiento deben ser específicos y medibles. Controla métricas como latencia (usando percentiles, no solo promedios), uso de memoria (conjunto de trabajo vs. bytes privados) y tiempo de CPU bajo condiciones de carga definidas para saber si alcanzas tus objetivos.

Automatiza la medición. Integra el monitoreo de rendimiento en tus entornos de desarrollo, pruebas y producción. Herramientas como Contadores de Rendimiento y eventos ETW permiten seguimiento continuo y análisis histórico, proporcionando datos sólidos para respaldar mejoras y detectar regresiones rápidamente.

2. Domina la Memoria: Trabaja Con el Recolector de Basura.

Recoge objetos en la generación 0 o no los recojas.

El recolector de basura (GC) es una característica, no un error. El GC de .NET simplifica la gestión de memoria, pero requiere comprensión para optimizar el rendimiento. El principio clave es que los objetos sean muy efímeros (limpiados rápido en colecciones de Gen 0) o muy duraderos (promovidos a Gen 2 y mantenidos indefinidamente, a menudo mediante pooling).

Reduce la tasa de asignación y la vida útil de los objetos. El tiempo que tarda el GC depende de los objetos vivos, no de los asignados. Minimiza la asignación de memoria, especialmente para objetos grandes (>= 85,000 bytes) que van al Heap de Objetos Grandes (LOH), costosos de recolectar y propensos a fragmentación. Usa pools para objetos grandes o de uso frecuente y evita asignaciones repetidas.

Comprende la configuración del GC. Elige Workstation GC para aplicaciones de escritorio y Server GC para servidores dedicados para aprovechar la recolección paralela. El GC en segundo plano (por defecto) permite colecciones de Gen 2 concurrentes. Usa modos de baja latencia o compactación del LOH con moderación y medición cuidadosa, pues implican compromisos importantes.

3. Optimiza el JIT: Controla el Inicio y la Generación de Código.

La primera vez que se llama a un método siempre hay un impacto en el rendimiento.

El JIT añade costo al inicio. El código .NET se compila a Lenguaje Intermedio (IL) y luego se compila Just-In-Time (JIT) a código nativo en la primera ejecución. Este costo inicial puede afectar el tiempo de arranque o la capacidad de respuesta de la primera llamada a un método.

Reduce el tiempo de JIT. Minimiza la cantidad de código que necesita JIT, especialmente en rutas críticas de inicio. Ten en cuenta que ciertas características del lenguaje y APIs generan mucho IL oculto, como:

  • La palabra clave dynamic
  • async y await (aunque sus beneficios suelen superar los costos)
  • Expresiones regulares (especialmente las no compiladas o complejas)
  • Generación de código (por ejemplo, serializadores)

Aprovecha la precompilación. Para mejorar el inicio, usa Profile Optimization (Multicore JIT) para precompilar código frecuente basado en perfiles. En apps Universal Windows Platform, .NET Native compila a código nativo anticipadamente. En otros casos, NGEN (Native Image Generator) puede precompilar ensamblados, aunque con compromisos en localidad y tamaño del código.

4. Abraza la Asincronía: Evita Bloqueos, Maximiza el Rendimiento.

Para obtener el máximo rendimiento debes asegurarte de que tu programa nunca desperdicie un recurso esperando otro.

El paralelismo es clave para el rendimiento. Las aplicaciones modernas deben aprovechar múltiples núcleos de CPU. La programación asíncrona es esencial para evitar que los hilos se bloqueen en operaciones de E/S (red, disco, base de datos) u otros recursos, permitiendo que el sistema use eficazmente los ciclos de CPU mientras espera.

Usa Tasks y async/await. La Biblioteca de Tareas Paralelas (TPL) y las palabras clave async/await son la forma preferida de manejar concurrencia en .NET. Abstraen la gestión del pool de hilos y simplifican flujos asíncronos complejos, haciendo que el código parezca lineal sin bloquear.

Nunca bloquees en E/S o Tasks. Evita llamadas síncronas de E/S y nunca uses .Wait() o .Result en un Task en código crítico para rendimiento. En su lugar, usa await o .ContinueWith() para programar trabajo posterior, permitiendo que el hilo actual regrese al pool y atienda otras tareas.

5. Programa con Inteligencia: Elige Tipos y Patrones con Criterio.

La optimización profunda del rendimiento a menudo desafía las abstracciones del código.

Comprende el costo de los tipos. Las clases (tipos por referencia) tienen sobrecarga por instancia y viven en el heap, afectando al GC. Las estructuras (tipos por valor) no tienen sobrecarga y viven en la pila o inline dentro de otros objetos, ofreciendo mejor localidad de memoria, especialmente en arrays. Elige structs para datos pequeños y usados frecuentemente para reducir presión sobre el GC y mejorar el rendimiento de caché.

Cuidado con costos ocultos. Características del lenguaje y APIs pueden ocultar operaciones costosas. Las propiedades son llamadas a métodos, no acceso directo a campos. foreach sobre IEnumerable puede ser más lento que for en arrays por la sobrecarga del enumerador. Los casts, especialmente hacia abajo en la jerarquía o a interfaces, tienen costos de rendimiento.

Optimiza operaciones comunes. Para structs, implementa siempre Equals, GetHashCode (IEquatable<T>) y CompareTo (IComparable<T>) eficientemente para evitar implementaciones por defecto basadas en reflexión y habilitar operaciones optimizadas en colecciones. Usa retornos y variables ref en C# 7+ para evitar copias de structs grandes o accesos repetidos a elementos de arrays.

6. Conoce tu Framework: Entiende el Costo de las APIs.

Debes comprender el código que se ejecuta detrás de cada API llamada.

Las APIs del framework tienen compromisos. El .NET Framework es de propósito general; sus APIs priorizan corrección y usabilidad sobre rendimiento puro en muchos casos. No asumas que una llamada simple es barata, especialmente en rutas críticas.

Inspecciona y cuestiona las APIs. Usa descompiladores (como ILSpy) para examinar la implementación de métodos del Framework que usas frecuentemente. Busca costos ocultos como:

  • Asignaciones de memoria (especialmente en el LOH)
  • Bucles o algoritmos costosos
  • Dependencia de reflexión o comportamiento dinámico
  • Validaciones o manejo de errores innecesarios

Elige la herramienta adecuada. Para tareas comunes como colecciones, cadenas o E/S, .NET ofrece múltiples APIs con características de rendimiento variadas. Realiza benchmarks de alternativas (por ejemplo, diferentes parsers XML, métodos de concatenación de cadenas) para encontrar la mejor opción para tu escenario.

7. Aprovecha las Herramientas: ETW, Perfiles y Depuradores son tus Aliados.

PerfView, creado originalmente por el arquitecto de rendimiento de Microsoft .NET (y autor del prólogo de este libro) Vance Morrison, es uno de los mejores por su potencia.

Las herramientas son esenciales para el diagnóstico. El análisis efectivo del rendimiento depende de herramientas potentes para recopilar e interpretar datos. No te limites a los perfiles básicos del IDE; aprende a usar herramientas avanzadas a nivel de sistema.

Herramientas clave y sus usos:

  • PerfView: Recopila y analiza eventos ETW (CPU, GC, JIT, personalizados). Excelente para análisis de pilas, detección de puntos calientes de asignación y comprensión del comportamiento del GC.
  • WinDbg + SOS: Depurador potente para examinar el estado del heap gestionado, raíces de objetos, objetos fijados y pilas de hilos. Indispensable para análisis profundos de fugas de memoria.
  • Visual Studio Profiler: Herramientas amigables para análisis de uso de CPU y memoria durante el desarrollo.
  • Contadores de Rendimiento: Métricas a nivel de sistema para monitorear la salud general y uso de recursos a lo largo del tiempo.
  • Eventos ETW: Mecanismo de registro de bajo costo usado por el SO y CLR. Define eventos personalizados para correlacionar comportamiento de la aplicación con rendimiento del sistema.

Domina los datos. Estas herramientas suelen proporcionar datos en bruto (como eventos ETW o volcados de heap). Aprender a interpretarlos, correlacionando información de múltiples fuentes, es clave para una depuración efectiva del rendimiento.

8. El Rendimiento es Ingeniería: Diseña, Mide, Itera.

El trabajo de rendimiento nunca debe dejarse para el final, especialmente en sentido macro o arquitectónico.

El rendimiento es una característica de diseño. Como la seguridad o la usabilidad, el rendimiento debe considerarse desde el inicio, especialmente en sistemas grandes o complejos. Las decisiones arquitectónicas tienen el mayor impacto y son las más difíciles de cambiar después.

Sigue un proceso iterativo. La optimización del rendimiento no es una tarea única. Requiere monitoreo y refinamiento continuo durante todo el ciclo de vida de la aplicación.

  1. Define objetivos y métricas.
  2. Diseña/implementa con rendimiento en mente.
  3. Mide contra los objetivos.
  4. Identifica cuellos de botella.
  5. Optimiza (primero macro, luego micro).
  6. Repite.

Fomenta una cultura de rendimiento. Promueve la conciencia sobre rendimiento en tu equipo. Automatiza pruebas y monitoreo, revisa código en busca de anti-patrones de rendimiento y prioriza correcciones basadas en datos.

9. Evita Errores Comunes: Excepciones, Boxing, Dynamic, Reflexión.

Las excepciones son muy costosas de lanzar.

Las excepciones son para casos excepcionales. Lanzar excepciones implica una sobrecarga significativa (recorrido de pila, creación de objetos) y no debe usarse para control de flujo o errores esperados. Usa métodos TryParse en lugar de Parse cuando el formato de entrada sea incierto.

Minimiza el boxing. Envolver tipos por valor en objetos (int a object) crea asignaciones en heap y presión sobre el GC. Evita APIs que hacen boxing implícito (por ejemplo, String.Format con tipos por valor, colecciones antiguas no genéricas).

Evita dynamic y reflexión en rutas críticas. La palabra clave dynamic y APIs de reflexión (como MethodInfo.Invoke) tienen una sobrecarga considerable por resolución de tipos en tiempo de ejecución y generación de código. Úsalos con moderación, especialmente en código crítico para rendimiento. Si la invocación dinámica es necesaria, considera la generación de código (System.Reflection.Emit) como alternativa.

10. Macro Antes que Micro: Prioriza la Arquitectura.

Las optimizaciones macro casi siempre son más beneficiosas que las micro.

Prioriza los esfuerzos de optimización. Cuando surjan problemas de rendimiento, comienza examinando los niveles más altos de tu sistema:

  • Arquitectura: ¿Es eficiente el diseño general? ¿Usas las tecnologías adecuadas?
  • Algoritmos: ¿Son apropiados para el tamaño de datos y patrones de acceso (complejidad Big O)?
  • Estructuras de datos: ¿Usas colecciones y tipos que se ajustan a tus patrones de uso y necesidades de memoria?

Las micro-optimización vienen al final. Solo después de abordar problemas de alto nivel debes profundizar en micro-optimización como ajustar implementaciones de métodos individuales, reducir asignaciones menores u optimizar bucles pequeños. Estos aportan ganancias menores y pueden ocultar problemas mayores si se hacen prematuramente.

La seducción de la simplicidad: La facilidad de uso de .NET puede llevar a escribir código ineficiente rápidamente. Entender los costos subyacentes de construcciones aparentemente simples es crucial para evitar construir sistemas lentos con rapidez.

Última actualización:

Reseñas

4.31 de 5
Promedio de 290 calificaciones de Goodreads y Amazon.

Escribir código .NET de alto rendimiento ha recibido críticas positivas, con una calificación promedio de 4.31 sobre 5. Los lectores valoran sus consejos prácticos para optimizar aplicaciones .NET, destacando su utilidad especialmente para programadores avanzados en C#. El libro es elogiado por abordar diversos temas relacionados con el rendimiento, como la recolección de basura y la compilación Just-In-Time (JIT). Mientras algunos consideran que es imprescindible para sistemas donde el rendimiento es crítico, otros señalan que no todas las aplicaciones requieren este nivel de optimización. Algunos pocos esperaban un análisis más profundo, dado el historial del autor en Microsoft, pero en general se considera un recurso sólido para desarrolladores .NET.

Your rating:
4.62
3 calificaciones

Sobre el autor

Ben Watson es ingeniero de software en Microsoft desde 2008, especializado en aplicaciones de servidor de alto rendimiento. Ha contribuido de manera significativa a la plataforma Bing, desarrollando un sistema basado en .NET que gestiona solicitudes de alto volumen y baja latencia en miles de máquinas. La experiencia de Watson en la optimización del rendimiento en .NET se refleja en la autoría de dos libros técnicos. Más allá de su trabajo profesional, disfruta de intereses variados como el geocaching, la lectura, la música clásica y el tiempo en familia. Su trayectoria en Microsoft y su papel en la creación de sistemas eficientes a gran escala lo han consolidado como una autoridad en la optimización del rendimiento en .NET.

Listen
Now playing
Writing High-Performance .NET Code
0:00
-0:00
Now playing
Writing High-Performance .NET Code
0:00
-0:00
1x
Voice
Speed
Dan
Andrew
Michelle
Lauren
1.0×
+
200 words per minute
Queue
Home
Library
Get App
Create a free account to unlock:
Recommendations: Personalized for you
Requests: Request new book summaries
Bookmarks: Save your favorite books
History: Revisit books later
Ratings: Rate books & see your ratings
100,000+ readers
Try Full Access for 7 Days
Listen, bookmark, and more
Compare Features Free Pro
📖 Read Summaries
All summaries are free to read in 40 languages
🎧 Listen to Summaries
Listen to unlimited summaries in 40 languages
❤️ Unlimited Bookmarks
Free users are limited to 4
📜 Unlimited History
Free users are limited to 4
📥 Unlimited Downloads
Free users are limited to 1
Risk-Free Timeline
Today: Get Instant Access
Listen to full summaries of 73,530 books. That's 12,000+ hours of audio!
Day 4: Trial Reminder
We'll send you a notification that your trial is ending soon.
Day 7: Your subscription begins
You'll be charged on Jun 22,
cancel anytime before.
Consume 2.8x More Books
2.8x more books Listening Reading
Our users love us
100,000+ readers
"...I can 10x the number of books I can read..."
"...exceptionally accurate, engaging, and beautifully presented..."
"...better than any amazon review when I'm making a book-buying decision..."
Save 62%
Yearly
$119.88 $44.99/year
$3.75/mo
Monthly
$9.99/mo
Start a 7-Day Free Trial
7 days free, then $44.99/year. Cancel anytime.
Scanner
Find a barcode to scan

Settings
General
Widget
Loading...