Start Debugging

performance

82 posts · Página1de9

iterador con yield return vs devolver una List<T>: lo que realmente cuesta un método IEnumerable en C#

Un método con yield return cuesta un objeto de máquina de estados de 40 bytes por llamada, sin importar cuántos elementos produzca; una List<T> cuesta todo el arreglo interno por adelantado. Medido en .NET 10.0.10: el iterador gana en memoria y en salida anticipada, List<T> gana cuando el llamador enumera más de una vez, necesita Count o llama a ToList().

Bucle con ref T vs indexación de Span<T> en C#: por qué la versión con span es igual de rápida o más en .NET 10

En .NET 10, un bucle for normal sobre span[i] acotado por span.Length se compila a un bucle sin comprobación de límites, con reducción de intensidad y cuenta regresiva. Un bucle escrito a mano con Unsafe.Add(ref r, i) y un índice int conserva una extensión de signo y una comparación con cuenta progresiva, y midió entre 2 y 5% más lento. Benchmarks y desensamblado del JIT para arm64 y x64 en .NET 10.0.10.

Lazy<T> vs LazyInitializer.EnsureInitialized vs double-checked locking en C#

Usa Lazy<T> por defecto: ejecuta la factory una sola vez, almacena en caché las excepciones y sus lecturas son demasiado baratas para medirlas tras la inicialización. Usa LazyInitializer.EnsureInitialized cuando inicializas de forma diferida muchos campos o posiciones de un arreglo y no puedes pagar un objeto extra por valor. El double-checked locking escrito a mano casi nunca vale la pena en .NET 10.

Qué es el layout transparente de un struct y por qué un struct envoltorio de un solo campo cambia la convención de llamada en .NET

Un struct transparente es aquel que el ABI trata exactamente igual que su único campo. .NET 11 no ofrece esa garantía: un struct que envuelve un double se pasa en RCX en Windows x64 pero en XMM0 en Linux y macOS. Aquí está el desensamblado del JIT de .NET 11 en tres ABI, los errores de P/Invoke que provoca y cómo escribir tipos envoltorio seguros en cualquier frontera.
Siguiente