AYUDA .NET

C# Span (Cómo funciona para desarrolladores)

Publicado en 6 de marzo, 2024
Compartir:

Span es un tipo introducido en C# 7.2 como parte del Spanstruct en el espacio de nombres System. Está diseñado para representar una región contigua de memoria arbitraria. A diferencia de los arrays o colecciones como managed heap, Span no posee la memoria de la pila o región de memoria a la que apunta; en su lugar, proporciona una vista ligera sobre los bloques de memoria existentes. Esta característica hace que Span sea especialmente potente para escenarios en los que se necesita trabajar con búferes de memoria de forma eficiente sin incurrir en sobrecarga adicional y escenarios de código inseguro. Más adelante en este artículo, también veremos la introducción alBiblioteca IronPDF deIron Software.

Características clave de Span

1. Gestión de la memoria

Span en C# permite a los desarrolladores trabajar directamente con la memoria sin recurrir a las tradicionales asignaciones de heap. Ofrece una forma de crear porciones de memoria a partir de matrices existentes u otras fuentes de memoria, eliminando la necesidad de copias de memoria adicionales.

2. Abstracciones de copia cero

Una de las características más destacadas de C# Span son sus abstracciones de copia cero. En lugar de duplicar datos, Span proporciona una forma de referenciar la memoria existente de forma eficiente. Esto es especialmente beneficioso en situaciones en las que copiar grandes cantidades de datos sería poco práctico o demasiado costoso.

3. Operaciones con puntero

Aunque C# ha sido tradicionalmente un lenguaje de alto nivel y seguro, Span introduce cierto grado de manipulación de memoria de bajo nivel similar al trabajo con punteros en lenguajes como C o C++. Los desarrolladores pueden realizar operaciones de tipo puntero sin sacrificar la seguridad y la naturaleza gestionada de C#.

4. Naturaleza inmutable

A pesar de sus capacidades de acceso a memoria de bajo nivel, C# Span sigue siendo inmutable. Esto significa que, aunque permite la manipulación de la memoria, refuerza la seguridad impidiendo modificaciones no intencionadas.

Ejemplo

using System;
class Program
{
    void Main()
    {
        int[] array = { 1, 2, 3, 4, 5 };
        // Create a span that points to the entire array
        Span<int> span = array;
        // Modify the data using the span
        span[2] = 10;
        // Print the modified array
        foreach (var item in array)
        {
            Console.WriteLine(item);
        }
    }
}
using System;
class Program
{
    void Main()
    {
        int[] array = { 1, 2, 3, 4, 5 };
        // Create a span that points to the entire array
        Span<int> span = array;
        // Modify the data using the span
        span[2] = 10;
        // Print the modified array
        foreach (var item in array)
        {
            Console.WriteLine(item);
        }
    }
}
Imports System
Friend Class Program
	Private Sub Main()
		Dim array() As Integer = { 1, 2, 3, 4, 5 }
		' Create a span that points to the entire array
		Dim span As Span(Of Integer) = array
		' Modify the data using the span
		span(2) = 10
		' Print the modified array
		For Each item In array
			Console.WriteLine(item)
		Next item
	End Sub
End Class
VB   C#

ReadOnlySpan

Mientras Spanes mutable y permite modificar los datos subyacentes, ReadOnlySpanes una vista inmutable de la memoria. Proporciona una interfaz de sólo lectura a una región contigua de memoria, lo que la hace adecuada para escenarios en los que sólo se necesita leer los datos sin modificarlos.

He aquí algunos puntos clave.

1. Vista de sólo lectura

Como su nombre indica, ReadOnlySpanpermite crear una vista de sólo lectura de un bloque de memoria. Esto significa que no se pueden modificar los elementos a través de un ReadOnlySpan.

2. Representación de la memoria

Como Span, ReadOnlySpanno es propietaria de la memoria a la que apunta. Se refiere a la memoria existente y puede apuntar a matrices, memoria asignada a pilas o memoria nativa.

3. Beneficios de rendimiento

Como Span, ReadOnlySpanpuede ofrecer un mejor rendimiento en comparación con los tipos de recogida tradicionales, especialmente cuando se trata de grandes cantidades de datos, ya que reduce la necesidad de realizar copias.

4. No Bounds Checking

Al igual que con Span, ReadOnlySpanno realiza la comprobación de límites. Es responsabilidad del desarrollador asegurarse de que las operaciones se mantienen dentro de los límites de la memoria subyacente.

5. Utilización con Array Slicing

ReadOnlySpanadmite el troceado, lo que permite crear subámbitos que hacen referencia a una parte de la memoria original.

Ejemplo

using System;
class Program
{
    static void Main()
    {
        int[] array = { 1, 2, 3, 4, 5 };
        // Create a read-only span that points to the entire array
        ReadOnlySpan<int> readOnlySpan = array;
        // Access and print the data through the read-only span
        foreach (var item in readOnlySpan)
        {
            Console.WriteLine(item);
        }
        // Note: The following line would result in a compilation error since readOnlySpan is read-only.
        // readOnlySpan[2] = 10;
    }
}
using System;
class Program
{
    static void Main()
    {
        int[] array = { 1, 2, 3, 4, 5 };
        // Create a read-only span that points to the entire array
        ReadOnlySpan<int> readOnlySpan = array;
        // Access and print the data through the read-only span
        foreach (var item in readOnlySpan)
        {
            Console.WriteLine(item);
        }
        // Note: The following line would result in a compilation error since readOnlySpan is read-only.
        // readOnlySpan[2] = 10;
    }
}
Imports System
Friend Class Program
	Shared Sub Main()
		Dim array() As Integer = { 1, 2, 3, 4, 5 }
		' Create a read-only span that points to the entire array
		Dim readOnlySpan As ReadOnlySpan(Of Integer) = array
		' Access and print the data through the read-only span
		For Each item In readOnlySpan
			Console.WriteLine(item)
		Next item
		' Note: The following line would result in a compilation error since readOnlySpan is read-only.
		' readOnlySpan[2] = 10;
	End Sub
End Class
VB   C#

Hay muchas maneras diferentes de crear ReadOnlySpan y trabajar con él. A continuación figuran algunos ejemplos.

1. Creación de ReadOnlySpan a partir de String

string msg = "Hello, World!";
ReadOnlySpan<char> span1 = msg.AsSpan();
// Read-only manipulation
char firstChar = span1[0];
Console.WriteLine(firstChar); // Outputs: H
string msg = "Hello, World!";
ReadOnlySpan<char> span1 = msg.AsSpan();
// Read-only manipulation
char firstChar = span1[0];
Console.WriteLine(firstChar); // Outputs: H
Dim msg As String = "Hello, World!"
Dim span1 As ReadOnlySpan(Of Char) = msg.AsSpan()
' Read-only manipulation
Dim firstChar As Char = span1(0)
Console.WriteLine(firstChar) ' Outputs: H
VB   C#

2. Trabajar con subcadenas

Utilizar Slice en el ReadOnlySpan

ReadOnlySpan<char> substringSpan = spanFromString.Slice(startIndex, length);
ReadOnlySpan<char> substringSpan = spanFromString.Slice(startIndex, length);
Dim substringSpan As ReadOnlySpan(Of Char) = spanFromString.Slice(startIndex, length)
VB   C#

3. Pasar una subcadena a un método

Pasar ReadOnlySpancomo parámetro del método.

void ProcessSubstringfromReadOnlySpan(ReadOnlySpan<char> substring)
{
    // Perform operations on the substring
}
// Usage
ProcessSubstringfromReadOnlySpan(spanFromString.Slice(startIndex, length));
void ProcessSubstringfromReadOnlySpan(ReadOnlySpan<char> substring)
{
    // Perform operations on the substring
}
// Usage
ProcessSubstringfromReadOnlySpan(spanFromString.Slice(startIndex, length));
Private Sub ProcessSubstringfromReadOnlySpan(ByVal substring As ReadOnlySpan(Of Char))
	' Perform operations on the substring
End Sub
' Usage
ProcessSubstringfromReadOnlySpan(spanFromString.Slice(startIndex, length))
VB   C#

4. Búsqueda dentro de una cadena

ReadOnlySpanpara buscar dentro de una cadena con IndexOf().

int index = stringSpan.IndexOf('W');
int index = stringSpan.IndexOf('W');
Dim index As Integer = stringSpan.IndexOf("W"c)
VB   C#

5. Uso de archivos mapeados en memoria

ReadOnlySpanpuede ser más eficiente con archivos mapeados en memoria.

using (var memmf = MemoryMappedFile.CreateFromFile("data.bin"))
{
    using (var accessor = memmf.CreateViewAccessor())
    {
        ReadOnlySpan<byte> dataSpan;
        accessor.Read(0, out dataSpan);
        // Process data directly from the memory-mapped file
        ProcessData(dataSpan);
    }
}
using (var memmf = MemoryMappedFile.CreateFromFile("data.bin"))
{
    using (var accessor = memmf.CreateViewAccessor())
    {
        ReadOnlySpan<byte> dataSpan;
        accessor.Read(0, out dataSpan);
        // Process data directly from the memory-mapped file
        ProcessData(dataSpan);
    }
}
Using memmf = MemoryMappedFile.CreateFromFile("data.bin")
	Using accessor = memmf.CreateViewAccessor()
		Dim dataSpan As ReadOnlySpan(Of Byte) = Nothing
		accessor.Read(0, dataSpan)
		' Process data directly from the memory-mapped file
		ProcessData(dataSpan)
	End Using
End Using
VB   C#

6. Manipulación eficiente de cadenas

ReadOnlySpanpuede utilizarse para una manipulación eficaz de las cadenas.

// Replace a character in a substring without creating a new string
spanFromString.Slice(startIndex, length).CopyTo(newSpan);
// Replace a character in a substring without creating a new string
spanFromString.Slice(startIndex, length).CopyTo(newSpan);
' Replace a character in a substring without creating a new string
spanFromString.Slice(startIndex, length).CopyTo(newSpan)
VB   C#

7. Pasar subcadena a las API

Cuando se trabaja con bibliotecas externas o API que operan con intervalos de caracteres.

void ExternalApiMethod(ReadOnlySpan<char> data)
{
    // Call the external API with the character span
}
// Usage
ExternalApiMethod(spanFromString.Slice(startIndex, length));
void ExternalApiMethod(ReadOnlySpan<char> data)
{
    // Call the external API with the character span
}
// Usage
ExternalApiMethod(spanFromString.Slice(startIndex, length));
Private Sub ExternalApiMethod(ByVal data As ReadOnlySpan(Of Char))
	' Call the external API with the character span
End Sub
' Usage
ExternalApiMethod(spanFromString.Slice(startIndex, length))
VB   C#

ReadOnlySpanproporciona una forma de trabajar con cadenas de forma más eficiente, especialmente en escenarios en los que las asignaciones de memoria y las copias deben minimizarse. Se trata de una potente herramienta para optimizar el rendimiento del código crítico y puede resultar especialmente beneficiosa cuando se trabaja con grandes cantidades de datos de cadenas.

Limitaciones de amplitud

Aunque Span en C# es una potente función con numerosas ventajas, conlleva ciertas limitaciones y consideraciones, especialmente en el contexto de la memoria contigua y no contigua. Exploremos estas limitaciones:

1. Memoria intermedia contigua

1.1 Sin gestión automática de la memoria

Spanno gestiona la memoria a la que apunta. Esto significa que si la memoria gestionada subyacente se libera o sale de ámbito, el uso de la función Spanprovocará un comportamiento indefinido o posibles fallos. Los desarrolladores deben asegurarse de que la memoria subyacente sigue siendo válida cuando se utiliza un Span.

1.2 Sin recogida de basura

Desde Spanno posee memoria, no está sujeta a la recolección de basura. Por lo tanto, debe tener cuidado cuando trabaje con memoria asignada a pilas o memoria que tenga un tiempo de vida más corto que la memoria Spansí mismo.

1.3 Comprobación de límites desactivada

Spany ReadOnlySpanno realizan la comprobación de límites por defecto. Esto puede llevar a acceder a posiciones de memoria no válidas si no se utiliza con cuidado. Los desarrolladores deben asegurarse manualmente de que las operaciones en un Spanpermanecer dentro de los límites de la memoria subyacente.

1.4 Sin soporte para memoria no contigua

Spanestá diseñado para trabajar con memoria contigua. Si dispone de memoria no contigua o necesita representar estructuras de datos más complejas, Spanpuede no ser la opción más adecuada.

1.5 No todas las operaciones son compatibles

Mientras Spanadmite muchas operaciones comunes como trocear, indexar e iterar, pero no todas las operaciones son compatibles. Por ejemplo, no se puede cambiar el tamaño de un Spany ciertas operaciones que implican cambiar la longitud de la memoria subyacente no están permitidas.

1.6 Compatibilidad limitada de plataformas

Mientras Spanforma parte de .NET Standard y .NET Core, es posible que no esté disponible en todas las plataformas o entornos. Es crucial asegurarse de que la plataforma de destino es compatible con Spansi piensa utilizarlo en su código.

2. Búferes de memoria no contiguos

2.1 Soporte limitado para memoria no contigua

ReadOnlySpanestá diseñado principalmente para trabajar sin problemas con bloques de memoria contiguos o buffers. Puede que no sea la opción más adecuada para escenarios en los que intervienen memorias intermedias no contiguas o estructuras con huecos en la memoria.

2.2 Limitaciones estructurales

Ciertas estructuras de datos o escenarios que dependen de memoria no contigua pueden no alinearse bien con ReadOnlySpan. Por ejemplo, las estructuras de datos como las listas enlazadas o las estructuras de grafos podrían no ser adecuadas debido a los requisitos de memoria contigua de ReadOnlySpan.

2.3 Operaciones complejas con punteros

En situaciones que implican memoria no contigua, particularmente aquellas que requieren aritmética de punteros compleja, ReadOnlySpanpuede no ofrecer el mismo control y flexibilidad de bajo nivel que los punteros sin formato en lenguajes como C++. En tales casos, utilizar código inseguro con punteros podría ser más apropiado.

2.4 Falta de soporte directo en algunas API

Al igual que ocurre con la memoria contigua, es importante tener en cuenta que no todas las API o bibliotecas admiten directamente la memoria no contigua representada por ReadOnlySpan. La adaptación a este tipo de escenarios puede requerir pasos intermedios adicionales o conversiones para garantizar la compatibilidad.

Span y memoria no gestionada

En C#, Span puede utilizarse eficazmente con memoria no gestionada para realizar operaciones relacionadas con la memoria de forma controlada y eficiente. La memoria no gestionada se refiere a la memoria que no está gestionada por el recolector de basura del tiempo de ejecución de .NET, y a menudo implica el uso de asignaciones y desasignaciones de memoria nativa. He aquí cómo se puede utilizar Span con memoria no gestionada en C#.

Asignación de memoria no gestionada

Para asignar memoria no gestionada, puede utilizar la clase System.Runtime.InteropServices.MemoryMarshal. El método Marshal.AllocHGlobal asigna memoria y devuelve un puntero al bloque asignado. La memoria asignada o dirección de memoria se mantiene en un puntero unmanagedMemory y tendrá acceso de lectura-escritura. Se puede acceder fácilmente a las regiones contiguas de la memoria.

using System;
using System.Runtime.InteropServices;
class Program
{
    static void Main()
    {
        const int bufferSize = 100;
        IntPtr unmanagedMemory = Marshal.AllocHGlobal(bufferSize);
        // Create a Span from the unmanaged memory
        Span<byte> span = new Span<byte>(unmanagedMemory.ToPointer(), bufferSize);
        // Use the Span as needed...
        // Don't forget to free the unmanaged memory when done
        Marshal.FreeHGlobal(unmanagedMemory);
    }
}
using System;
using System.Runtime.InteropServices;
class Program
{
    static void Main()
    {
        const int bufferSize = 100;
        IntPtr unmanagedMemory = Marshal.AllocHGlobal(bufferSize);
        // Create a Span from the unmanaged memory
        Span<byte> span = new Span<byte>(unmanagedMemory.ToPointer(), bufferSize);
        // Use the Span as needed...
        // Don't forget to free the unmanaged memory when done
        Marshal.FreeHGlobal(unmanagedMemory);
    }
}
Imports System
Imports System.Runtime.InteropServices
Friend Class Program
	Shared Sub Main()
		Const bufferSize As Integer = 100
		Dim unmanagedMemory As IntPtr = Marshal.AllocHGlobal(bufferSize)
		' Create a Span from the unmanaged memory
		Dim span As New Span(Of Byte)(unmanagedMemory.ToPointer(), bufferSize)
		' Use the Span as needed...
		' Don't forget to free the unmanaged memory when done
		Marshal.FreeHGlobal(unmanagedMemory)
	End Sub
End Class
VB   C#

En el código fuente anterior, asignamos un bloque de memoria no gestionada utilizando Marshal.AllocHGlobal y luego creamos un Spanutilizando el puntero obtenido de la memoria no gestionada. Esto nos permite trabajar con memoria no gestionada utilizando la conocida API Span. Es importante tener en cuenta que cuando se trabaja con memoria no gestionada, usted es responsable de la gestión de la asignación y desasignación de la memoria.

Copia de datos desde y hacia la memoria no gestionada

Span proporciona métodos como Slice, CopyTo y ToArray que pueden utilizarse para copiar datos entre memoria gestionada y no gestionada de forma eficiente.

using System;
using System.Runtime.InteropServices;
class Program
{
    static void Main()
    {
        // Managed array to copy data from
        int[] sourceArray = { 1, 2, 3, 4, 5 };
        // Allocate unmanaged memory for the destination data
        IntPtr destinationPointer = MemoryMarshal.Allocate<int>(sourceArray.Length);
        try
        {
            // Create a Span<int> from the source array
            Span<int> sourceSpan = sourceArray;
            // Create a Span<int> from the allocated unmanaged memory
            Span<int> destinationSpan = MemoryMarshal.Cast<int, byte>(destinationPointer, sourceArray.Length);
            // Copy data from the source Span<int> to the destination Span<int>
            sourceSpan.CopyTo(destinationSpan);
            // Print the values in the destination memory
            Console.WriteLine("Values in the destination memory:");
            foreach (var value in destinationSpan)
            {
                Console.Write($"{value} ");
            }
        }
        finally
        {
            // Deallocate the unmanaged memory when done
            MemoryMarshal.Free(destinationPointer);
        }
    }
}
using System;
using System.Runtime.InteropServices;
class Program
{
    static void Main()
    {
        // Managed array to copy data from
        int[] sourceArray = { 1, 2, 3, 4, 5 };
        // Allocate unmanaged memory for the destination data
        IntPtr destinationPointer = MemoryMarshal.Allocate<int>(sourceArray.Length);
        try
        {
            // Create a Span<int> from the source array
            Span<int> sourceSpan = sourceArray;
            // Create a Span<int> from the allocated unmanaged memory
            Span<int> destinationSpan = MemoryMarshal.Cast<int, byte>(destinationPointer, sourceArray.Length);
            // Copy data from the source Span<int> to the destination Span<int>
            sourceSpan.CopyTo(destinationSpan);
            // Print the values in the destination memory
            Console.WriteLine("Values in the destination memory:");
            foreach (var value in destinationSpan)
            {
                Console.Write($"{value} ");
            }
        }
        finally
        {
            // Deallocate the unmanaged memory when done
            MemoryMarshal.Free(destinationPointer);
        }
    }
}
Imports System
Imports System.Runtime.InteropServices
Friend Class Program
	Shared Sub Main()
		' Managed array to copy data from
		Dim sourceArray() As Integer = { 1, 2, 3, 4, 5 }
		' Allocate unmanaged memory for the destination data
		Dim destinationPointer As IntPtr = MemoryMarshal.Allocate(Of Integer)(sourceArray.Length)
		Try
			' Create a Span<int> from the source array
			Dim sourceSpan As Span(Of Integer) = sourceArray
			' Create a Span<int> from the allocated unmanaged memory
			Dim destinationSpan As Span(Of Integer) = MemoryMarshal.Cast(Of Integer, Byte)(destinationPointer, sourceArray.Length)
			' Copy data from the source Span<int> to the destination Span<int>
			sourceSpan.CopyTo(destinationSpan)
			' Print the values in the destination memory
			Console.WriteLine("Values in the destination memory:")
			For Each value In destinationSpan
				Console.Write($"{value} ")
			Next value
		Finally
			' Deallocate the unmanaged memory when done
			MemoryMarshal.Free(destinationPointer)
		End Try
	End Sub
End Class
VB   C#

En este ejemplo:

MemoryMarshal.Allocate(sourceArray.Length) asigna memoria no gestionada para los datos de destino. MemoryMarshal.Cast<int, byte>(destinationPointer, sourceArray.Length) crea un Spande la memoria no gestionada asignada. El sourceSpan.CopyTo(destinationSpan) copia los datos de la matriz gestionada a la memoria no gestionada. Los valores de la memoria de destino se imprimen para verificar la operación de copia. La MemoriaMarshal.Free(destinationPointer) se utiliza para desasignar la memoria no gestionada una vez finalizado el proceso.

Uso de código inseguro

Cuando se trabaja con memoria no gestionada, también se puede utilizar código inseguro con punteros. En tales casos, puede obtener un puntero del Span utilizando el método Unsafe.AsPointer() método.

using System;
using System.Runtime.InteropServices;
class Program
{
    static void Main()
    {
        const int bufferSize = 100;
        IntPtr unmanagedMemory = Marshal.AllocHGlobal(bufferSize);
        // Create a Span from the unmanaged memory
        Span<byte> span = new Span<byte>(unmanagedMemory.ToPointer(), bufferSize);
        // Use unsafe code to work with pointers
        // ref t
        unsafe
        {
            byte* pointer = (byte*)Unsafe.AsPointer(ref struct MemoryMarshal.GetReference(span));
            // Use the pointer as needed...
        }
        // Don't forget to free the unmanaged memory when done
        Marshal.FreeHGlobal(unmanagedMemory);
    }
}
using System;
using System.Runtime.InteropServices;
class Program
{
    static void Main()
    {
        const int bufferSize = 100;
        IntPtr unmanagedMemory = Marshal.AllocHGlobal(bufferSize);
        // Create a Span from the unmanaged memory
        Span<byte> span = new Span<byte>(unmanagedMemory.ToPointer(), bufferSize);
        // Use unsafe code to work with pointers
        // ref t
        unsafe
        {
            byte* pointer = (byte*)Unsafe.AsPointer(ref struct MemoryMarshal.GetReference(span));
            // Use the pointer as needed...
        }
        // Don't forget to free the unmanaged memory when done
        Marshal.FreeHGlobal(unmanagedMemory);
    }
}
Imports System
Imports System.Runtime.InteropServices
Friend Class Program
	Shared Sub Main()
		Const bufferSize As Integer = 100
		Dim unmanagedMemory As IntPtr = Marshal.AllocHGlobal(bufferSize)
		' Create a Span from the unmanaged memory
		Dim span As New Span(Of Byte)(unmanagedMemory.ToPointer(), bufferSize)
		' Use unsafe code to work with pointers
		' ref t
'INSTANT VB TODO TASK: C# 'unsafe' code is not converted by Instant VB:
'		unsafe
'		{
'			byte* pointer = (byte*)Unsafe.AsPointer(ref struct MemoryMarshal.GetReference(span));
'			' Use the pointer as needed...
'		}
		' Don't forget to free the unmanaged memory when done
		Marshal.FreeHGlobal(unmanagedMemory)
	End Sub
End Class
VB   C#

En este ejemplo, utilizamos el método Unsafe.AsPointer para obtener un puntero del Span. Esto nos permite utilizar código inseguro cuando trabajamos directamente con punteros.

Recuerde que, cuando se trabaja con memoria no gestionada, es crucial gestionar la asignación y desasignación correctamente para evitar fugas de memoria. Libere siempre la memoria no gestionada utilizando métodos adecuados, como Marshal.FreeHGlobal(). Además, tenga cuidado al utilizar código no seguro, ya que puede introducir posibles riesgos de seguridad si no se maneja adecuadamente.

Span y llamadas a métodos asíncronos

El uso de Span junto con llamadas a métodos asíncronos en C# es una potente combinación, especialmente cuando se trata de grandes cantidades de datos u operaciones de E/S. El objetivo es manejar las operaciones asíncronas sin copias innecesarias de datos de forma eficiente. Exploremos cómo puede aprovechar Span en escenarios asíncronos:

1. Operaciones de E/S asíncronas:

Cuando se trata de operaciones de E/S asíncronas, como la lectura o escritura de datos en un flujo, puede utilizar Memoryo Spanpara trabajar eficazmente con los datos sin crear búferes adicionales.

async Task ProcessDataAsync(Stream stream)
{
    const int bufferSize = 4096;
    byte[] buffer = new byte[bufferSize];
    while (true)
    {
        int bytesRead = await stream.ReadAsync(buffer.AsMemory());
        if (bytesRead == 0)
            break;
        // Process the data using Span without unnecessary copying
        ProcessData(buffer.AsSpan(0, bytesRead));
    }
}
void ProcessData(Span<byte> data)
{
    // Perform operations on the data
}
async Task ProcessDataAsync(Stream stream)
{
    const int bufferSize = 4096;
    byte[] buffer = new byte[bufferSize];
    while (true)
    {
        int bytesRead = await stream.ReadAsync(buffer.AsMemory());
        if (bytesRead == 0)
            break;
        // Process the data using Span without unnecessary copying
        ProcessData(buffer.AsSpan(0, bytesRead));
    }
}
void ProcessData(Span<byte> data)
{
    // Perform operations on the data
}
Async Function ProcessDataAsync(ByVal stream As Stream) As Task
	Const bufferSize As Integer = 4096
	Dim buffer(bufferSize - 1) As Byte
	Do
		Dim bytesRead As Integer = Await stream.ReadAsync(buffer.AsMemory())
		If bytesRead = 0 Then
			Exit Do
		End If
		' Process the data using Span without unnecessary copying
		ProcessData(buffer.AsSpan(0, bytesRead))
	Loop
End Function
Private Sub ProcessData(ByVal data As Span(Of Byte))
	' Perform operations on the data
End Sub
VB   C#

En este ejemplo, el método ReadAsync lee asíncronamente datos de un flujo en el búfer. A continuación, el método ProcessData procesa los datos directamente desde el Spansin copiarlo en otro búfer.

2. Operaciones asíncronas de archivos:

De forma similar a las operaciones de E/S, cuando se trata de operaciones de archivo asíncronas, puede utilizar Span para procesar datos de forma eficiente sin necesidad de realizar copias adicionales.

async Task ProcessFileAsync(string filePath)
{
    const int bufferSize = 4096;
    using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
    {
        byte[] buffer = new byte[bufferSize];
        while (true)
        {
            int bytesRead = await fileStream.ReadAsync(buffer.AsMemory());
            if (bytesRead == 0)
                break;
            // Process the data using Span without unnecessary copying
            ProcessData(buffer.AsSpan(0, bytesRead));
        }
    }
}
void ProcessData(Span<byte> data)
{
    // Perform operations on the data
}
async Task ProcessFileAsync(string filePath)
{
    const int bufferSize = 4096;
    using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
    {
        byte[] buffer = new byte[bufferSize];
        while (true)
        {
            int bytesRead = await fileStream.ReadAsync(buffer.AsMemory());
            if (bytesRead == 0)
                break;
            // Process the data using Span without unnecessary copying
            ProcessData(buffer.AsSpan(0, bytesRead));
        }
    }
}
void ProcessData(Span<byte> data)
{
    // Perform operations on the data
}
Async Function ProcessFileAsync(ByVal filePath As String) As Task
	Const bufferSize As Integer = 4096
	Using fileStream As New FileStream(filePath, FileMode.Open, FileAccess.Read)
		Dim buffer(bufferSize - 1) As Byte
		Do
			Dim bytesRead As Integer = Await fileStream.ReadAsync(buffer.AsMemory())
			If bytesRead = 0 Then
				Exit Do
			End If
			' Process the data using Span without unnecessary copying
			ProcessData(buffer.AsSpan(0, bytesRead))
		Loop
	End Using
End Function
Private Sub ProcessData(ByVal data As Span(Of Byte))
	' Perform operations on the data
End Sub
VB   C#

Aquí, el método ReadAsync lee datos de un flujo de archivos en el búfer, y el método ProcessData procesa los datos directamente desde el Span.

3. Procesamiento de tareas asíncronas:

Cuando se trabaja con tareas asíncronas que producen o consumen datos, se puede utilizar Memoryo Spanpara evitar copias innecesarias.

async Task<int> ProcessDataAsync(int[] data)
{
    // Asynchronous processing of data
    await Task.Delay(1000);
    // Returning the length of the processed data
    return data.Length;
}
async Task Main()
{
    int[] inputData = Enumerable.Range(1, 1000).ToArray();
    // Process the data asynchronously without copying
    int processedLength = await ProcessDataAsync(inputData.AsMemory());
    Console.WriteLine($"Processed data length: {processedLength}");
}
async Task<int> ProcessDataAsync(int[] data)
{
    // Asynchronous processing of data
    await Task.Delay(1000);
    // Returning the length of the processed data
    return data.Length;
}
async Task Main()
{
    int[] inputData = Enumerable.Range(1, 1000).ToArray();
    // Process the data asynchronously without copying
    int processedLength = await ProcessDataAsync(inputData.AsMemory());
    Console.WriteLine($"Processed data length: {processedLength}");
}
Async Function ProcessDataAsync(ByVal data() As Integer) As Task(Of Integer)
	' Asynchronous processing of data
	Await Task.Delay(1000)
	' Returning the length of the processed data
	Return data.Length
End Function
Async Function Main() As Task
	Dim inputData() As Integer = Enumerable.Range(1, 1000).ToArray()
	' Process the data asynchronously without copying
	Dim processedLength As Integer = Await ProcessDataAsync(inputData.AsMemory())
	Console.WriteLine($"Processed data length: {processedLength}")
End Function
VB   C#

En este ejemplo, el método ProcessDataAsync procesa los datos de forma asíncrona y devuelve la longitud de los datos procesados sin necesidad de copias adicionales.

Presentación de IronPDF

Visión general de la biblioteca IronPDF es la última biblioteca PDF en C# deIron Software que puede utilizarse para generar hermosos documentos PDF sobre la marcha de forma dinámica utilizando código C#. IronPDF ofrece diversas funciones, como la generación de PDF a partir de HTML, la conversión de contenido HTML a PDF, la fusión o división de archivos PDF, etc.

La principal característica de IronPDF es suFuncionalidad de HTML a PDFla traducción debe ser profesional, conservando la precisión técnica y explicando las características y ventajas de estas herramientas para desarrolladores. Puede generar archivos PDF a partir de contenido web, por lo que es ideal para informes, facturas y documentación. Esta herramienta permite convertir archivos HTML, URL y cadenas HTML en archivos PDF.

using IronPdf;

class Program
{
    static void Main(string[] args)
    {
        var renderer = new ChromePdfRenderer();

        // 1. Convert HTML String to PDF
        var htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>";
        var pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent);
        pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf");

        // 2. Convert HTML File to PDF
        var htmlFilePath = "path_to_your_html_file.html"; // Specify the path to your HTML file
        var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
        pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");

        // 3. Convert URL to PDF
        var url = "http://ironpdf.com"; // Specify the URL
        var pdfFromUrl = renderer.RenderUrlAsPdf(url);
        pdfFromUrl.SaveAs("URLToPDF.pdf");
    }
}
using IronPdf;

class Program
{
    static void Main(string[] args)
    {
        var renderer = new ChromePdfRenderer();

        // 1. Convert HTML String to PDF
        var htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>";
        var pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent);
        pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf");

        // 2. Convert HTML File to PDF
        var htmlFilePath = "path_to_your_html_file.html"; // Specify the path to your HTML file
        var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
        pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");

        // 3. Convert URL to PDF
        var url = "http://ironpdf.com"; // Specify the URL
        var pdfFromUrl = renderer.RenderUrlAsPdf(url);
        pdfFromUrl.SaveAs("URLToPDF.pdf");
    }
}
Imports IronPdf

Friend Class Program
	Shared Sub Main(ByVal args() As String)
		Dim renderer = New ChromePdfRenderer()

		' 1. Convert HTML String to PDF
		Dim htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>"
		Dim pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent)
		pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf")

		' 2. Convert HTML File to PDF
		Dim htmlFilePath = "path_to_your_html_file.html" ' Specify the path to your HTML file
		Dim pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath)
		pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf")

		' 3. Convert URL to PDF
		Dim url = "http://ironpdf.com" ' Specify the URL
		Dim pdfFromUrl = renderer.RenderUrlAsPdf(url)
		pdfFromUrl.SaveAs("URLToPDF.pdf")
	End Sub
End Class
VB   C#

Instalación

IronPDF puede instalarse mediante la aplicaciónGestor de paquetes NuGet para IronPDF o mediante el gestor de paquetes de Visual Studio.

dotnet add package IronPdf
// Or
Install-Package IronPdf
dotnet add package IronPdf
// Or
Install-Package IronPdf
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'dotnet add package IronPdf Install-Package IronPdf
VB   C#

C# Span(Cómo funciona para desarrolladores): Figura 1 - Instale IronPDF utilizando NuGet Package Manager buscando ironpdf en la barra de búsqueda de NuGet Package Manager

using System;
class Program
{
    static void Main()
    {
        Console.WriteLine("Generating PDF using IronPDF.");
        var displayFirstName = "<p>First Name is Joe</p>".AsSpan();
        var displayLastName = "<p>First Name is Doe</p>".AsSpan();
        var displayAddress = "<p>12th Main, 7Th Cross, New York</p>".AsSpan();
        var start = @"<!DOCTYPE html>
<html>
<body>".AsSpan();
        var end = @"<!DOCTYPE html>
<html>
<body>";
        var content = string.Concat(start, displayFirstName, displayLastName, string.Concat(displayAddress, end));
        var pdfDocument = new ChromePdfRenderer();
        pdfDocument.RenderHtmlAsPdf(content).SaveAs("span.pdf");
    }
}
using System;
class Program
{
    static void Main()
    {
        Console.WriteLine("Generating PDF using IronPDF.");
        var displayFirstName = "<p>First Name is Joe</p>".AsSpan();
        var displayLastName = "<p>First Name is Doe</p>".AsSpan();
        var displayAddress = "<p>12th Main, 7Th Cross, New York</p>".AsSpan();
        var start = @"<!DOCTYPE html>
<html>
<body>".AsSpan();
        var end = @"<!DOCTYPE html>
<html>
<body>";
        var content = string.Concat(start, displayFirstName, displayLastName, string.Concat(displayAddress, end));
        var pdfDocument = new ChromePdfRenderer();
        pdfDocument.RenderHtmlAsPdf(content).SaveAs("span.pdf");
    }
}
Imports System
Friend Class Program
	Shared Sub Main()
		Console.WriteLine("Generating PDF using IronPDF.")
		Dim displayFirstName = "<p>First Name is Joe</p>".AsSpan()
		Dim displayLastName = "<p>First Name is Doe</p>".AsSpan()
		Dim displayAddress = "<p>12th Main, 7Th Cross, New York</p>".AsSpan()
		Dim start = "<!DOCTYPE html>
<html>
<body>".AsSpan()
		Dim [end] = "<!DOCTYPE html>
<html>
<body>"
		Dim content = String.Concat(start, displayFirstName, displayLastName, String.Concat(displayAddress, [end]))
		Dim pdfDocument = New ChromePdfRenderer()
		pdfDocument.RenderHtmlAsPdf(content).SaveAs("span.pdf")
	End Sub
End Class
VB   C#

En este ejemplo, estamos utilizando Span junto con IronPDF para generar un documento PDF.

Salida:

C# Span(Cómo funciona para desarrolladores): Figura 2 - Salida de la consola

PDF generado:

C# Span(Cómo funciona para desarrolladores): Figura 3 - Salida PDF

Licencias (prueba gratuita disponible)

Información sobre la licencia de IronPDF. Esta clave debe colocarse en appsettings.json.

"IronPdf.LicenseKey": "your license key"
"IronPdf.LicenseKey": "your license key"
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'"IronPdf.LicenseKey": "your license key"
VB   C#

Proporcione su correo electrónico para obtener una licencia de prueba.

Conclusión

Spanen C# proporciona una forma potente y eficaz de trabajar con la memoria, ofreciendo ventajas en términos de rendimiento y flexibilidad. Su naturaleza no propietaria y contigua la hace especialmente adecuada para escenarios en los que es crucial minimizar las asignaciones y copias de memoria. Gracias a Span, los desarrolladores pueden mejorar el rendimiento de diversas aplicaciones, desde la manipulación de cadenas hasta el procesamiento numérico de alto rendimiento. Comprendiendo sus características y teniendo en cuenta sus limitaciones, los desarrolladores pueden aprovechar Spanpara diversas tareas de manipulación de la memoria de forma segura y eficaz. Junto conVisión general de la biblioteca IronPDF, se puede utilizar para generar impresionantes documentos PDF sin límites de espera y rendimiento.

VisitePágina de documentación de inicio rápido de IronPDF página.

< ANTERIOR
C# IDE (Cómo funciona para los desarrolladores)
SIGUIENTE >
Opentelemetry C# (Cómo funciona para desarrolladores)

¿Listo para empezar? Versión: 2024.12 acaba de salir

Descarga gratuita de NuGet Descargas totales: 11,622,374 Ver licencias >