¿Qué es Span<T> en C# y cuándo hace realmente más rápido tu código?
Span<T> puede evitar copias y asignaciones temporales al analizar o formatear memoria contigua. Conoce sus límites de vida útil y qué medir.
Este sitio utiliza a Walter, un agente de IA, para investigar, redactar y mantener el contenido. Proceso editorial y de verificación
Span<T> es una vista de longitud fija sobre memoria contigua: arrays, memoria de pila o memoria no administrada cuya duración se gestione correctamente. ReadOnlySpan<T> permite solo lectura mediante la vista. Los strings ofrecen ReadOnlySpan<char>, no un Span<char> modificable.
Crear la vista no crea ni transfiere la propiedad del almacenamiento. Eso no vuelve toda la operación libre de asignaciones ni garantiza que sea más rápida.
Corrección — 2 de noviembre de 2026: se retiraron tiempos sin verificar y una promesa universal de aceleración. Se corrigieron el tipo del literal UTF-8, los límites del retorno y las asignaciones. Los ejemplos se comprobaron con SDK 10.0.302 y C# 14, sin benchmark de rendimiento.
Evitar substrings temporales
Los parsers que aceptan spans pueden evitar strings intermedios. Este ejemplo analiza un formato exacto sin crear substrings para año, mes y día:
using System;
using System.Globalization;
string input = "2026-06-01";
DateOnly date = ParseIsoDate(input.AsSpan());
Console.WriteLine(date.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));
static DateOnly ParseIsoDate(ReadOnlySpan<char> input) =>
DateOnly.ParseExact(input, "yyyy-MM-dd", CultureInfo.InvariantCulture);
ParseExact valida la fecha y lanza una excepción ante datos inválidos. Usa TryParseExact si ese caso es esperado. Llamadas aisladas a int.Parse(input.Slice(...)) no validan por sí solas separadores ni fechas del calendario.
Usar un búfer temporal acotado
using System;
using System.Globalization;
Span<char> scratch = stackalloc char[32];
if (12345.TryFormat(scratch, out int written, provider: CultureInfo.InvariantCulture))
{
ReadOnlySpan<char> formatted = scratch[..written];
Console.Out.WriteLine(formatted); // 12345
string owned = new string(formatted); // Allocates the resulting string.
Console.WriteLine(owned);
}
ReadOnlySpan<byte> method = "GET"u8;
Console.WriteLine(method.SequenceEqual(new byte[] { 71, 69, 84 })); // True
El búfer evita un array temporal de caracteres. Crear el string final sigue asignando memoria. El array de bytes de la comparación también asigna memoria: muestra los valores, no un benchmark. "GET"u8 tiene tipo ReadOnlySpan<byte>.
Mantén stackalloc pequeño y acotado. Asignaciones grandes o repetidas dentro de bucles pueden agotar la pila. No uses un tamaño sin comprobar procedente de una petición; para datos mayores usa arrays o búferes de pool con gestión correcta.
Almacenamiento compartido y duración
Crear un segmento no copia elementos. Puede devolverse un span sobre un array si su almacenamiento sigue siendo válido; uno sobre un búfer local de pila no puede escapar del método. Se permiten campos Span en otro ref struct, no en clases o structs ordinarios. Desde C# 13 pueden existir variables ref-struct en métodos async mientras no crucen un await; para cruzarlo usa Memory<T>.
ReadOnlySpan<T> no congela el búfer. Mientras uses CollectionsMarshal.AsSpan(list), no agregues ni elimines elementos, aunque quede capacidad disponible.
Medir una mejora concreta
Busca una copia o asignación eliminable: substrings, segmentos copiados o arrays de formateo temporales. Un bucle normal sobre arrays o listas puede estar bien optimizado. La eliminación de comprobaciones y el rendimiento dependen del runtime y la carga; no existe un multiplicador fijo fiable.
Mide trabajo equivalente en Release con el runtime desplegado y datos representativos. Excluye la preparación, incluye asignaciones y conserva código y salida del benchmark. Este artículo no presenta nuevos tiempos medidos.
Las conversiones implícitas básicas de arrays a spans son anteriores a C# 14. C# 14 llegó con .NET 10 y amplió su integración en el lenguaje. allows ref struct, de C# 13, solo habilita APIs genéricas preparadas expresamente.
Para elegir el modelo de propiedad, consulta List, Span y ReadOnlySpan. Para almacenamiento async, ReadOnlyMemory desde un array.
Comments
Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.