.NET 帮助

C# Span(开发人员如何使用)

发布 2024年三月6日
分享:

跨度 是 C# 7.2 中引入的一种类型,是 Span译文将使用 System 名称空间中的 struct。 它旨在表示任意内存的连续区域。 与数组或集合(如托管堆)不同,Span并不拥有堆栈内存或其指向的内存区域; 此外,译文还必须提供对现有内存块的轻量级视图。 这一特点使得 Span 在需要高效处理内存缓冲区而又不产生额外开销和不安全代码的情况下特别强大。 在本文后面,我们还将看到对IronPDF 库铁软件.

跨度的主要特征

1.内存管理

C# 中的 Span 允许开发人员直接使用内存,而无需借助传统的堆分配。 它提供了一种从现有数组或其他内存源创建内存片的方法,无需额外的内存副本。

2.零拷贝抽象

C# Span 的突出特点之一是其零拷贝抽象。 Span 提供了一种有效引用现有内存的方法,而不是重复数据。 这对于复制大量数据不切实际或成本过高的情况尤为有利。

3.类指针操作

C# 传统上是一种高级、安全的语言,而 Span 则引入了一定程度的低级内存操作,类似于在 C# 或 C++ 等语言中使用指针。 开发人员可以在不牺牲 C# 的安全性和托管性质的前提下执行指针式操作。

4.不可改变的性质

尽管 C# Span 具有底层内存访问功能,但它仍然是不可变的。 这意味着,在允许对内存进行操作的同时,还要通过防止意外修改来确保安全性。

示例

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是一种不可变的内存视图。 它为内存的连续区域提供了一个只读接口,因此适用于只需读取数据而无需修改的情况。

以下是一些要点。

1.只读视图

顾名思义,ReadOnlySpan允许您创建内存块的只读视图。 这意味着您不能通过 ReadOnlySpan 来修改元素。.

2.记忆表述

喜欢跨度, ReadOnlySpan不拥有其指向的内存。 它指的是现有内存,可以指向数组、堆栈分配内存或本地内存。

3.性能优势

喜欢跨度, ReadOnlySpan与传统的收集类型相比,它可以提供更好的性能,尤其是在处理大量数据时,因为它减少了复制的需要。

4.无边界检查

与 Span, ReadOnlySpan不执行边界检查。 开发人员有责任确保操作不超出底层内存的范围。

5.使用数组切片

只读跨度支持分片,允许你创建子跨度来引用原始内存的一部分。

示例

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#

创建 ReadOnlySpan 并使用它的方法有很多种。 下面是一些例子。

1.从字符串创建 ReadOnlySpan

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.使用子字符串

在 ReadOnlySpan 上使用 Slice

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.向方法传递子串

通过 ReadOnlySpan作为方法的参数。

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.在字符串内搜索

只读跨度用于使用 IndexOf 在字符串内搜索().

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

5.使用内存映射文件

只读跨度可以更高效地处理内存映射文件。

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.高效的字符串操作

只读跨度可用于高效的字符串操作。

// 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.向应用程序接口传递子串

在使用以字符跨度为操作单位的外部库或 API 时。

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#

只读跨度该工具提供了一种更高效地处理字符串的方法,尤其是在需要尽量减少内存分配和复制的情况下。 它是优化性能关键型代码的强大工具,在处理大量字符串数据时尤其有用。

跨度限制

虽然 C# 中的 Span 功能强大,优点众多,但也存在一定的局限性和注意事项,尤其是在连续和非连续内存的情况下。 让我们来探讨一下这些限制:

1.连续内存缓冲区

1.1 没有自动内存管理

跨度不管理其指向的内存。 这意味着,如果底层托管内存被释放或超出范围,使用 Span在翻译过程中,如果出现错误,将导致未定义的行为或潜在的崩溃。 开发人员需要确保在使用 Span 语言时,底层内存仍然有效。.

1.2 无垃圾回收

由于跨度由于.NET、Java、Python 或 Node.js 不拥有内存,因此不受垃圾回收的影响。 因此,在使用堆栈分配内存或寿命短于 Span 的内存时,您需要小心谨慎。它本身。

1.3 禁用边界检查

跨度和 ReadOnly跨度默认情况下不执行边界检查。 如果使用不慎,可能会导致访问无效的内存位置。 开发人员需要手动确保对一个 Span保持在底层内存的范围内。

1.4 不支持非连续内存

跨度该工具的设计可与连续内存一起使用。 如果您有非连续内存或需要表示更复杂的数据结构,Span可能不是最合适的选择。

1.5 并非所有操作都支持

同时该工具支持许多常见操作,如切片、索引和迭代,但并不支持所有操作。 例如,您不能调整 Span以及某些涉及改变底层内存长度的操作是不允许的。

1.6 有限的平台兼容性

同时虽然.NET Core 是 .NET Standard 和 .NET Core 的一部分,但它可能不适用于所有平台或环境。 确保您的目标平台支持跨语言是至关重要的。如果您打算在代码中使用它。

2.非连续内存缓冲区

2.1 对非连续内存的有限支持

只读跨度该工具的主要设计目的是与连续的内存块或缓冲区无缝协作。 对于涉及非连续内存缓冲区或内存中有间隙的结构的场景,可能不是最合适的选择。

2.2 结构限制

某些依赖非连续内存的数据结构或场景可能与 ReadOnlySpan 不匹配。. 例如,由于 ReadOnlySpan 的连续内存要求,链接列表或图形结构等数据结构可能并不适合。.

2.3 复杂指针操作

在涉及非连续内存的情况下,特别是那些需要复杂指针运算的情况下,ReadOnlySpan指针可能无法提供与 C++ 等语言中的原始指针相同的底层控制和灵活性。 在这种情况下,使用带有指针的不安全代码可能更合适。

2.4 某些应用程序接口缺乏直接支持

与连续内存类似,需要注意的是,并非所有 API 或库都直接支持 ReadOnlySpan 所代表的非连续内存。. 为适应此类场景,可能需要额外的中间步骤或转换,以确保兼容性。

跨度和非托管内存

在 C# 中,Span 可以有效地与非托管内存配合使用,以受控和高效的方式执行与内存相关的操作。 非托管内存指的是不受 .NET 运行时垃圾回收器管理的内存,通常涉及使用本地内存分配和取消分配。 以下是 Span 如何利用 C# 中的非托管内存。

分配非托管内存

要分配非托管内存,您可以使用 System.Runtime.InteropServices.MemoryMarshal 类。 Marshal.AllocHGlobal方法分配内存并返回指向已分配区块的指针。 分配的内存或内存地址保存在非托管内存指针中,并具有读写访问权限。 可以方便地访问内存中的连续区域。

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#

在上述源代码中,我们使用 Marshal.AllocHGlobal 分配了一个非托管内存块,然后创建了一个 Span使用从非托管内存中获取的指针。 这样,我们就可以使用熟悉的 Span API 来处理非托管内存。 需要注意的是,在使用非托管内存时,您需要负责管理内存的分配和删除。

将数据复制到非托管内存或从非托管内存复制数据

Span 提供了 Slice、CopyTo 和 ToArray 等方法,可用于在托管和非托管内存之间高效复制数据。

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#

在此示例中:

MemoryMarshal.Allocate(sourceArray.Length)为目标数据分配非托管内存。 MemoryMarshal.Cast<int, byte>(destinationPointer, sourceArray.Length) 创建一个跨度从分配的非托管内存中调用。 sourceSpan.CopyTo(目的地跨度)方法将数据从托管数组复制到非托管内存。 打印目标存储器中的值以验证复制操作。 MemoryMarshal.Free(目的地指针)方法来完成非托管内存的重新分配。

使用不安全代码

在处理非托管内存时,您还可能使用带有指针的不安全代码。 在这种情况下,您可以使用 Unsafe.AsPointer 从 Span 中获取指针。()方法。

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#

在本例中,我们使用 Unsafe.AsPointer 方法从 Span 中获取一个指针。 这使得我们在直接使用指针时可以使用不安全的代码。

请记住,在使用非托管内存时,正确管理分配和取消分配以避免内存泄漏至关重要。 始终使用适当的方法释放非托管内存,如 Marshal.FreeHGlobal(). 此外,在使用不安全代码时要谨慎,因为如果处理不当,可能会带来潜在的安全风险。

跨和异步方法调用

将 Span 与 C# 中的异步方法调用结合使用是一种强大的组合,尤其是在处理大量数据或 I/O 操作时。 目标是有效处理异步操作,避免不必要的数据复制。 让我们探讨一下如何在异步场景中利用 Span:

1. 异步 I/O 操作:

在处理异步 I/O 操作(如向流中读写数据)时,您可以使用 Memory或跨度以便在不创建额外缓冲区的情况下高效处理数据。

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#

在本例中,ReadAsync 方法异步地将数据从流读入缓冲区。 然后,ProcessData 方法会直接处理 SpanData 中的数据。而不复制到另一个缓冲区。

2. 异步文件操作:

与 I/O 操作类似,在处理异步文件操作时,您可以使用 Span 高效处理数据,而无需额外复制。

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#

在这里,ReadAsync 方法将数据从文件流读入缓冲区,ProcessData 方法则直接处理来自 Span 的数据。.

3. 异步任务处理:

在处理产生或消耗数据的异步任务时,您可以使用 Memory或跨度以避免不必要的复制。

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#

在本例中,ProcessDataAsync 方法异步处理数据,并返回已处理数据的长度,而不需要额外的副本。

介绍IronPDF

IronPDF 库概述铁软件该工具可用于使用 C# 代码动态生成精美的 PDF 文档。 IronPDF 提供多种功能,如从 HTML 生成 PDF、将 HTML 内容转换为 PDF、合并或拆分 PDF 文件等。

IronPDF 的主要特点是其HTML 到 PDF 的功能此外,翻译还必须保留.NET、Java、Python 或 Node js 的布局和样式。 它可以从网页内容生成 PDF,因此非常适合报告、发票和文档。 该工具支持将 HTML 文件、URL 和 HTML 字符串转换为 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#

安装

IronPDF 可以通过以下方式安装IronPDF 的 NuGet 包管理器您可以使用 Visual Studio 软件包管理器或 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(如何为开发人员工作):图 1 - 在 NuGet 包管理器的搜索栏中搜索 ironpdf,使用 NuGet 包管理器安装 IronPDF

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#

在本例中,我们使用SpanIronPDF来生成 PDF 文档。

输出:

C# Span(如何为开发人员工作):图 2 - 控制台输出

生成 PDF:

C# Span(如何为开发人员工作):图 3 - PDF 输出

许可(可免费试用)

IronPDF 许可证信息. 这个密钥需要放置在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#

提供您的电子邮件以获取试用许可证。

结论

跨度.NET、Java、Python 或 Node js 中的 C# 提供了一种功能强大、高效的内存处理方式,在性能和灵活性方面具有优势。 其非自有、连续的特性使其特别适用于对内存分配和复制要求最低的场景。 通过利用 Span,开发人员可以在从字符串操作到高性能数字处理等各种应用中获得更好的性能。 通过了解其功能并考虑其局限性,开发人员可以利用 Span这些工具可以安全高效地执行各种内存操作任务。 同时IronPDF 库概述此外,该工具还可用于生成超棒的 PDF 文档,无等待和产量界限。

请访问IronPDF 快速入门文档页面page.

< 前一页
C# IDE(它如何为开发人员工作)
下一步 >
Opentelemetry C#(开发人员如何使用)

准备开始了吗? 版本: 2024.12 刚刚发布

免费NuGet下载 总下载量: 11,781,565 查看许可证 >