Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

202
Visualizações
Estructura de datos pequeños similar a List<T> sin asignación para .NET 5+

¿Existen estructuras de datos para .NET (las versiones recientes) que tengan un modo inicial "pequeño" que no asigne memoria? Algo que usaría inicialmente la memoria en la pila (stackalloc), luego, si todo eso está agotado, cambie a usar el montón y solo luego ejerza presión sobre GC. Una SmallList<T> con una interfaz similar a List<T> sería la más útil cuando sabe que, en la mayoría de los casos, solo se agregan algunos elementos.

En C++ hay al menos una buena implementación de esta idea utilizada en LLVM, SmallVector y algunos tipos pequeños similares para conjuntos/mapas. ¿Cuál es la diferencia entre std::vector y llvm::SmallVector? ¿Cuál usar cuando?
También este video: CppCon 2016: Chandler Carruth "Código de alto rendimiento 201: Estructuras de datos híbridas"

He estado buscando en Google un poco y no pude encontrar nada sobre una implementación existente, y si es posible hacerlo. Tendría que limitarse a los tipos de valor con más certeza, pero incluso entonces no estoy seguro de cómo escribiría algún valor T en la matriz stackalloc y lo volvería a leer, por ejemplo. si T es un int, ¿hay ahora una API para "reinterpret_cast" un rango de bytes de un intervalo a un int directamente, no combinando los 4 bytes uno por uno?

La estructura de datos más cercana a esta idea que pude encontrar es SStringBuilder de Towel lib: https://github.com/ZacharyPatten/Towel/blob/main/Sources/Towel/SStringBuilder.cs

 // SStringBuilder is a small helper for initializing strings. // It will append to the span until the capacity is reached // and then it will revert to a StringBuilder if necessary

Editar
Encontré esta API, puede ser lo que se necesita https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.memorymarshal.read


Editar 2

Hice una pequeña lista pirateada que solo funciona con una pequeña cantidad de valores, lanzando una excepción si se alcanza la capacidad en lugar de cambiar a una lista. Intenté algunas formas de hacer esto:

  • con Span y usando MemoryMarshal.Read/Write
  • con Span y leer/escribir directamente el span
  • con ArrayPool.Shared.Rent/Return
  • con una lista
  • con una Lista con capacidad preasignada en el constructor

Hasta cerca de 32 valores, las versiones Span son mucho más rápidas, a continuación se muestran algunos resultados de BenchmarkDotNet: el banco solo agrega N estructuras pequeñas (2 campos int) a la lista y luego obtiene cada valor y suma los campos. N era 1,2,4... y algunos más hasta 128, era curioso en qué punto desaparece la ventaja, en la práctica la parte de la pila debería ser para < 10 valores.

 Results for 2 values: | SpanListBench | 2 | 6.126 ns | 0.0188 ns | 0.0147 ns | | TypedSpanlListBench | 2 | 5.403 ns | 0.0147 ns | 0.0123 ns | | PoolListBench | 2 | 24.182 ns | 0.0375 ns | 0.0351 ns | | ListBench | 2 | 18.160 ns | 0.1737 ns | 0.1540 ns | | ListBenchPrealloc | 2 | 13.754 ns | 0.0978 ns | 0.0867 ns |
 Results for 8 values: | SpanListBench | 8 | 18.045 ns | 0.0494 ns | 0.0438 ns | | TypedSpanListBench | 8 | 16.467 ns | 0.0565 ns | 0.0472 ns | | PoolListBench | 8 | 31.558 ns | 0.0735 ns | 0.0651 ns | | ListBench | 8 | 44.527 ns | 0.1977 ns | 0.1849 ns | | ListBenchPrealloc | 8 | 29.989 ns | 0.2079 ns | 0.1736 ns |
 ref struct TypedSpanList<T> where T:struct { private Span<T> buffer_; private int count_; public TypedSpanList(Span<T> buffer) { buffer_ = buffer; count_ = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Add(T value) { if (count_ >= buffer_.Length) { throw new InvalidOperationException(); } buffer_[count_] = value; count_++; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public T Get(int index) { if (index >= buffer_.Length) { throw new InvalidOperationException(); } return buffer_[index]; } } [Benchmark] public int TypedListBench() { int count = 0; Span<Test> s = stackalloc Test[Number]; var sl = new TypedSpanList<Test>(s); for (int i = 0; i < Number; i++) { sl.Add(new Test() { a = i, b = i + 1 }); } for (int i = 0; i < Number; i++) { var t = sl.Get(i); count += ta + tb; } return count; }

over 4 years ago · Santiago Trujillo
1 Respostas
Responde à pergunta

0

Hasta donde yo sé, no hay una solución lista para usar de .NET.

La pregunta más importante es: ¿qué necesito? List tiene un mecanismo de control de versiones interno que verifica si se actualizó durante la iteración. ¿Necesitas eso para tu versión pequeña? La iteración es un tema desafiante en sí mismo: consulte la lista de go on de .NET .

Si usa una estructura (por referencia no le permite implementar ninguna interfaz además de IDisposable ), parte de su ganancia sin asignación podría perderse cuando habla a través de la interfaz (debido al boxeo).

Entonces, ¿qué es lo más importante? ¿Mutar sus elementos? pasando los elementos a lo largo? ¿Iterar a través de todos/algunos de los elementos?

Es obvio que podría ser una optimización prematura, así que asumo que ya lo tuvo en cuenta.

Y hasta donde yo sé, la inserción agresiva no funciona si lanzas excepciones en esos métodos.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda