C# avanzado — Misión
Secciones
Ajustes de lectura
Ninguna voz para este idioma en este navegador.
Más voces
Código y términos técnicos en inglés
Desactivado: la voz de la página lo lee todo, sin pausa entre dos voces.
Ninguna voz para este idioma en este navegador.
Más voces
Más voces: Microsoft Edge ofrece voces naturales en línea, y Windows (Configuración › Hora e idioma › Voz), macOS y Android instalan otras.
Por qué aprendo esto
Sección titulada «Por qué aprendo esto»Llevo años escribiendo C#, y la mayor parte de lo que sé sobre su rendimiento es folclore: «los structs son más rápidos», «evita LINQ», «usa siempre ConfigureAwait(false)», «FrozenDictionary es el rápido». Parte de ello era cierto en .NET Framework 4.5 y es falso en .NET 10, donde el JIT elimina asignaciones que el IL pide. Este curso sustituye cada pieza de folclore por algo que puedo observar: el tamaño de un objeto, el IL que emitió el compilador, la máquina de estados que hay detrás de await, la generación de un array, una tabla de BenchmarkDotNet.
Lo mismo vale para el código que mueve datos entre tareas y para ASP.NET Core. Uso canales y BackgroundService sin haber comprobado qué pasa cuando un consumidor se detiene antes de tiempo o un productor lanza una excepción, y configuro ASP.NET Core copiando lo que funcionó la última vez. Las partes posteriores del curso convierten también esas preguntas en programas.
Las mediciones se hacen sobre código real, no sobre clases de juguete: Guitar Alchemist (GA), una gran base de código .NET 10 sobre teoría musical. Sus objetos de valor, sus cachés, su generador de voicings y sus servicios hospedados son justo el tipo de código donde surgen estas preguntas, y las lecciones encontraron varios lugares donde GA paga por algo que no pretendía, o se bloquea donde debería fallar.
A quién va dirigido este curso
Sección titulada «A quién va dirigido este curso»Escribes C# a diario y conoces bien el lenguaje: genéricos, LINQ, async/await, records, coincidencia de patrones. Quieres saber qué hacen el compilador, el JIT, el recolector de basura y ASP.NET Core con ese código, y medir antes de optimizar. Si estás empezando con C#, comienza por el curso C# para principiantes, que termina donde empieza este.
Si también trabajas con Java, las partes 2 y 3 terminan cada lección con una tabla «Si conoces Spring y Reactor», de C# a Java. El curso de Spring Boot, Spring Cloud y Reactor va en sentido contrario, de ASP.NET Core a Spring; los dos cursos se enlazan entre sí en lugar de explicar dos veces lo mismo.
Al terminar este curso, sabré
Sección titulada «Al terminar este curso, sabré»- predecir el tamaño de un valor o de un objeto, detectar el boxing en el IL y saber cuándo lo elimina el JIT;
- usar
ref,in,ref readonly,Span<T>ystackallocsin copias defensivas ni referencias que escapan; - explicar las generaciones, los montones de objetos grandes y de objetos fijados y los modos del GC, y leer
GC.GetGCMemoryInfo; - leer la máquina de estados que el compilador genera para un método
async, elegir entreTaskyValueTask, y evitar interbloqueos y cancelaciones perdidas; - escribir un benchmark de BenchmarkDotNet que mida lo que creo que mide, e interpretar la compilación por niveles y la PGO;
- elegir entre
Dictionary,FrozenDictionary,SearchValuesy la aritmética simple, y vectorizar un bucle conVector<T>oTensorPrimitives; - conectar productores y consumidores con canales, TPL Dataflow, Rx.NET o
IAsyncEnumerable, y decir para cada uno qué ocurre con backpressure, ante un error y ante una cancelación; - seguir una petición a través de ASP.NET Core, de Kestrel al endpoint, y elegir con criterio las duraciones de los servicios, las opciones, los filtros, los servicios hospedados, la resiliencia y la caché;
- observar y probar un servicio ASP.NET Core, y publicarlo con Native AOT;
- y, en la última parte: árboles de expresión, generadores de código fuente, analizadores de Roslyn e interoperabilidad.
El ejemplo conductor
Sección titulada «El ejemplo conductor»Las partes 1 y 2 miden el propio código de GA. La parte 3 construye un pequeño servicio de escalas y acordes sobre los tipos de dominio de GA, el equivalente en ASP.NET Core del servicio de escalas del curso de Spring Boot, Spring Cloud y Reactor: los mismos endpoints, para que cada lección pueda comparar las dos implementaciones línea por línea.
Parte 1: runtime y rendimiento
Sección titulada «Parte 1: runtime y rendimiento»| # | Lección | Bajo el capó | Medido en GA | Spring y Reactor |
|---|---|---|---|---|
| 1 | Memoria: valores, referencias y spans | disposición de los objetos, boxing en el IL, ref/in, ref struct, Span<T>, stackalloc |
PitchClass, PitchClassSetId.ItemsSpan |
sin tipos por valor, genéricos borrados, liberar un DataBuffer |
| 2 | El recolector de basura | generaciones, LOH y POH, GC de estación de trabajo y de servidor, DATAS, finalizadores, GC.GetGCMemoryInfo |
asignaciones de ItemsSpan con [MemoryDiagnoser] |
G1 y ZGC, Cleaner, el -prof gc de JMH |
| 3 | async y await bajo el capó | la máquina de estados generada, ValueTask, SynchronizationContext, ConfigureAwait, cancelación, IAsyncEnumerable |
Try.OfAsync, LazyWithExpiration |
ensamblado y suscripción, publishOn, hilos virtuales |
| 4 | Rendimiento medido | BenchmarkDotNet, JIT por niveles y PGO, SearchValues, FrozenDictionary, Vector<T> |
resta de PitchClass, SimdOps.Dot |
JMH, C1 y C2, la API Vector |
| 5 | Genéricos en profundidad | restricciones, miembros abstractos estáticos, matemáticas genéricas, allows ref struct, cómo comparte el JIT el código genérico |
IStaticValueObjectList<TSelf> de GA |
el borrado, y genéricos sin primitivos |
Parte 2: concurrencia y flujo de datos
Sección titulada «Parte 2: concurrencia y flujo de datos»| # | Lección | Bajo el capó | Spring y Reactor |
|---|---|---|---|
| 6 | Channels | canales acotados y no acotados, modos de canal lleno, finalización y errores, varios productores y consumidores, cancelación; el generador de voicings y el comando de indexación de GA | onBackpressureBuffer, onBackpressureDrop, BlockingQueue |
| 7 | TPL Dataflow | bloques y enlaces, paralelismo y orden, BoundedCapacity, errores que solo bajan, finalización; la demo de Dataflow de GA |
flatMap con concurrencia, buffer, publishOn |
| 8 | Rx.NET | IObservable<T>, frío y caliente, operadores en tiempo virtual, schedulers, sin backpressure, reintentos; la demo reactiva de GA |
Flux, Sinks, publishOn, StepVerifier.withVirtualTime |
| 9 | Elegir un flujo | IAsyncEnumerable y System.Linq.AsyncEnumerable, los cuatro tipos de flujo medidos lado a lado, puentes, rendimiento, un diagrama de decisión |
Reactor: Mono y Flux, Reactor por dentro |
| 10 | Estado compartido y el grupo de subprocesos | System.Threading.Lock, Interlocked, colecciones concurrentes, Parallel.ForEachAsync, inanición del grupo de subprocesos |
synchronized, ReentrantLock, hilos virtuales |
Parte 3: ASP.NET Core en profundidad
Sección titulada «Parte 3: ASP.NET Core en profundidad»| # | Lección | Bajo el capó | Spring y Reactor |
|---|---|---|---|
| 11 | Hospedaje, WebApplication y Kestrel |
el host genérico, el builder, los límites de conexión y de petición de Kestrel, el apagado ordenado | Spring Boot visto desde ASP.NET Core, Tomcat y Netty embebidos |
| 12 | El pipeline de middlewares | Use, Map, Run, orden, cortocircuitos, manejo de excepciones, enrutamiento de endpoints |
filtros Servlet, WebFilter |
| 13 | Inyección de dependencias y opciones | duraciones, dependencias cautivas, validación de ámbitos, servicios con clave, IOptions, IOptionsSnapshot, IOptionsMonitor, validación |
el contenedor de Spring, @ConfigurationProperties |
| 14 | Minimal APIs y controladores | manejadores de rutas y enlace de parámetros, filtros, validación, TypedResults, respuestas IAsyncEnumerable en streaming |
@RestController, endpoints funcionales de WebFlux |
| 15 | Servicios hospedados | IHostedService, BackgroundService, orden de arranque y de apagado, excepciones, colas con canales; los servicios hospedados de GA |
@Scheduled, SmartLifecycle |
| 16 | Autenticación y autorización | esquemas, manejadores, JWT bearer, directivas y requisitos | Spring Security |
| 17 | Oráculos de especificación Petri para pipelines C# | modelos finitos de ciclo de vida, alcanzabilidad completa, clasificación terminal, compuertas de ejecución deterministas; colas Channel, ejecución/salidas retenidas de Dataflow y supuestos Rx mantenidos por separado | el mismo método se aplica a Reactor solo después de modelar explícitamente su capacidad y sus schedulers |
| 18 | gRPC y SignalR | contratos protobuf, llamadas en streaming, hubs, backpressure a través de la red | Spring gRPC, WebSocket, RSocket |
| 19 | Resiliencia, limitación de velocidad y caché de salida | Microsoft.Extensions.Http.Resilience, pipelines de Polly, limitadores de velocidad, directivas de caché de salida |
Resilience4j, Spring Cloud Circuit Breaker |
| 20 | OpenTelemetry y diagnóstico en producción | System.Diagnostics.Metrics, ActivitySource, exportadores de OpenTelemetry, dotnet-counters, dotnet-trace, dotnet-dump |
Micrometer, Actuator |
| 21 | Pruebas con WebApplicationFactory |
el host de pruebas, sustituir servicios, autenticación en las pruebas, Testcontainers | @SpringBootTest, WebTestClient |
| 22 | Native AOT y recorte | publicar una API con Native AOT, advertencias de recorte, el generador de delegados de solicitud, arranque y tamaño medidos | imágenes nativas de GraalVM |
Parte 4: metaprogramación y herramientas
Sección titulada «Parte 4: metaprogramación y herramientas»| # | Lección | Bajo el capó | Spring y Reactor |
|---|---|---|---|
| 23 | Árboles de expresión, reflexión y generadores de código fuente | en qué se compila una lambda, Expression<T>, el coste de la reflexión, generadores incrementales, [GeneratedRegex] |
procesadores de anotaciones, el motor AOT de Spring |
| 24 | Analizadores y correcciones de código de Roslyn | modelos sintácticos y semánticos, escribir un analizador y sus pruebas | Error Prone, SpotBugs |
| 25 | Interoperabilidad y código no seguro | [LibraryImport], punteros de función, Unsafe, MemoryMarshal, fijación |
JNI, y la API de funciones y memoria externas |
Apéndices
Sección titulada «Apéndices»| # | Página | Bajo el capó | Medido sobre GA |
|---|---|---|---|
| 1 | Cinco optimizaciones, demostradas y luego medidas | rotaciones y PopCount sobre conjuntos de 12 bits, tablas de consulta, una demostración de equivalencia sobre todo el dominio de entrada, los ordenamientos estables como desempate, y un benchmark que medía el JIT en lugar del código |
IsClusterFree, IntervalClassVector, ClosestDiatonicKey, ToNormalForm, PrimeForm |
| 2 | GA, perfilado, luego demostrado y medido | dotnet-trace sobre un pipeline real, máscaras de 12 bits en lugar de conjuntos hash, enumeradores encapsulados, una caché de 4096 casillas indexada por el propio conjunto, una propiedad LINQ en un bucle caliente, y una demostración que compara byte a byte dos compilaciones de GA |
CanonicalChordRecognizer, ChordIntervalPattern.TryMatch, IntervalClassVector, OptickIndexReader |
| 3 | Oráculo de ciclo de vida con redes de Petri | un pipeline acotado con éxito, fallo y cancelación explícitos; alcanzabilidad completa y ningún marcado muerto no terminal | las formas de fallo de Channel estudiadas en las lecciones 6 y 9 |
| 4 | Plugins sin MEF | un AssemblyLoadContext descargable por módulo, AssemblyDependencyResolver, un único contenedor de inyección de dependencias, dos versiones de una biblioteca lado a lado, la identidad de los tipos, y un temporizador que mantiene cargado su módulo |
no GA: cuatro módulos pequeños escritos para el apéndice |
| — | Diario |
Las lecciones 18 a 25 están planificadas y aún no se han escrito. La lección 17 es un laboratorio avanzado de concurrencia añadido después de las lecciones de ASP.NET Core; las lecciones 6 a 9 se escribieron antes que la lección 5 y no dependen de ella.
Requisitos previos
Sección titulada «Requisitos previos»- El SDK de .NET 10 y Git. En Windows, ejecuta los scripts del curso desde Git Bash.
check.shrestaurailspycmdcomo herramienta local de .NET (versión 11.0.0.9375, fijada en.config/dotnet-tools.json), descarga los tres proyectos de GA que usa el programa, unos 11 MB, y restauraSystem.Reactive7.0.0 para la lección 8, yNewtonsoft.Json13.0.3 y 13.0.1 para el apéndice 4.- Para los benchmarks, una máquina que puedas mantener tranquila durante unos minutos: cierra el navegador y enchufa el portátil.
Cursos relacionados en este sitio
Sección titulada «Cursos relacionados en este sitio»- C# para principiantes: el lenguaje desde cero, escrito al mismo tiempo que este curso.
- Spring Boot, Spring Cloud y Reactor para desarrolladores C#: las mismas preguntas desde el lado de Java, con el mismo ejemplo conductor.
- Teoría musical para Guitar Alchemist lee los mismos proyectos de GA por lo que calculan; este curso los lee por cómo se ejecutan.
- Rust para desarrolladores C#/Java hace explícito lo que .NET decide por ti: ownership en lugar de un recolector de basura, préstamos en lugar de las reglas de seguridad de
ref.
Recursos
Sección titulada «Recursos»- Fundamentos de .NET: administración de memoria y recolección de elementos no utilizados, y las opciones de configuración del GC.
- Referencia del lenguaje C#, en particular los ref structs y la programación asincrónica.
- Stephen Toub, Performance Improvements in .NET 10 y How async/await really works in C#, en el blog de .NET.
- El repositorio dotnet/runtime: las lecciones enlazan las líneas del runtime en las que se apoyan, en la etiqueta
v10.0.12(commit4271d88). - BenchmarkDotNet y sus buenas prácticas.
- Microsoft Learn: canales, TPL Dataflow, fundamentos de ASP.NET Core.
- Ian Griffiths y Lee Campbell, Introduction to Rx.NET, 2nd edition, gratuito en línea.
- Konrad Kokosa, Pro .NET Memory Management (Apress, 2018): anterior a .NET 10, sigue siendo el libro más profundo sobre el GC.