成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Span 在網(wǎng)絡編程中可以提供高性能的內(nèi)存訪問和數(shù)據(jù)處理能力

開發(fā) 前端
在 .NET 中,許多常見的數(shù)據(jù)類型,如 `string`、`array` 等,都是引用類型,它們本身并不包含實際的數(shù)據(jù),而是在堆上分配了一塊內(nèi)存來存儲數(shù)據(jù),然后將其地址傳遞給變量。

`Span<T>` 是 .NET Core 2.1 引入的一個新類型,它提供任意內(nèi)存的連續(xù)區(qū)域的類型安全和內(nèi)存安全表示形式。`Span<T>` 可以與任意的值類型或引用類型進行關聯(lián),包括原始內(nèi)存指針、數(shù)組、堆上對象等。通過 `Span<T>`,我們可以對這些數(shù)據(jù)結構進行高效的讀取和寫入操作,而無需進行拷貝或者分配額外的內(nèi)存。

在 .NET 中,許多常見的數(shù)據(jù)類型,如 `string`、`array` 等,都是引用類型,它們本身并不包含實際的數(shù)據(jù),而是在堆上分配了一塊內(nèi)存來存儲數(shù)據(jù),然后將其地址傳遞給變量。這種設計在很多情況下非常方便,但也會帶來一些性能上的問題,比如頻繁的內(nèi)存分配和釋放、GC 壓力等。`Span<T>` 的出現(xiàn)為解決這些問題提供了一種新的方式。

使用 `Span<T>`,我們可以盡可能地避免進行內(nèi)存分配和復制,從而提高代碼的運行效率。同時,由于 `Span<T>` 只是一個“視圖”,它并不會改變原始數(shù)據(jù)的內(nèi)容或生命周期,因此也非常安全可靠。在 .NET Core 中,許多常見的 API(如網(wǎng)絡、IO、序列化等)都已經(jīng)開始支持 `Span<T>`,這為我們編寫高性能、低延遲的代碼提供了更多的可能性。

Span是如何實現(xiàn)的?

通常不需要了解他們正在使用的庫是如何實現(xiàn)的。但是,就 Span<T> 而言,至少對其背后的細節(jié)有一個基本的了解是值得的,因為這些細節(jié)暗示了其性能和使用限制。

首先,Span<T> 是一個包含 ref 和長度的值類型,定義大致如下:

public readonly ref struct Span<T>
{
  private readonly ref T _pointer;
  private readonly int _length;
  ...
}

引用 T 字段的概念一開始可能很奇怪,事實上,實際上無法在 C# 甚至 MSIL 中聲明引用 T 字段。但 Span<T> 實際上是為在運行時中使用一種特殊的內(nèi)部類型而編寫的,該類型被視為實時 (JIT) 內(nèi)部類型,JIT 為其生成等效的 ref T 字段。考慮一個可能更熟悉的 ref 用法:

public static void AddOne(ref int value) => value += 1;
...
var values = new int[] { 42, 84, 126 };
AddOne(ref values[2]);
Assert.Equal(127, values[2]);

此代碼通過引用傳遞數(shù)組中的插槽,這樣(撇開優(yōu)化不談)堆棧上有一個 ref T。Span<T> 中的 ref T 是相同的想法,只是封裝在一個結構中。直接或間接包含此類 ref 的類型稱為類似 ref 的類型,C# 7.2 編譯器允許通過在簽名中使用 ref 結構來聲明此類類似 ref 的類型。

從這個簡短的描述中,應該清楚兩件事:

  • Span<T> 的定義方式使操作可以像數(shù)組一樣高效:索引到 span 中不需要計算來確定指針的起點及其起始偏移量,因為 ref 字段本身已經(jīng)封裝了兩者。(相比之下,ArraySegment<T> 具有單獨的偏移字段,因此索引和傳遞的成本更高。
  • Span<T> 作為類似 ref 類型的性質(zhì),由于其 ref T 字段而帶來了一些約束。

Span使用注意:

Span<T> 是在堆棧而不是托管堆上分配的 ref 結構 。 Ref 結構類型有許多限制,以確保它們不能提升到托管堆,包括不能裝箱、不能分配給 類型的Objectdynamic變量或任何接口類型,它們不能是引用類型中的字段,也不能跨 await 和 yield 邊界使用。 此外,對和 兩個NotSupportedException方法的 Equals(Object)GetHashCode調(diào)用會引發(fā) 。

因為它是僅堆棧類型, Span<T> 不適用于許多需要存儲對堆上的緩沖區(qū)的引用的方案。 例如,進行異步方法調(diào)用的例程也是如此。 對于此類方案,可以使用互補 System.Memory<T> 和 System.ReadOnlyMemory<T> 類型。

Span的應用場景

Span<T> 可以看作是一個指向連續(xù)內(nèi)存塊的引用,它可以用于訪問數(shù)組、堆棧、堆等數(shù)據(jù)結構中的連續(xù)元素。Span<T> 對象本身不會分配或釋放任何內(nèi)存,因此它非常適用于內(nèi)存密集型的應用場景,例如網(wǎng)絡編程、高性能計算等。

以下是一些 Span<T> 的常見應用場景:

  • 數(shù)組操作:Span<T> 可以用于訪問和操作數(shù)組中的元素,包括讀取、修改、排序等操作。與傳統(tǒng)的數(shù)組訪問方式相比,Span<T> 更加靈活和高效,可以有效地減少內(nèi)存分配和拷貝的開銷。
  • 文件操作:Span<T> 可以用于讀取和寫入文件中的二進制數(shù)據(jù)。通過使用 MemoryMappedFile 和 Span<T>,可以實現(xiàn)高效的文件讀寫操作,并且避免了不必要的內(nèi)存分配和拷貝。
  • 網(wǎng)絡編程:Span<T> 可以用于訪問網(wǎng)絡數(shù)據(jù)包中的二進制數(shù)據(jù),例如解析 TCP/IP 數(shù)據(jù)包、HTTP 請求等。通過使用 Span<T>,可以避免數(shù)據(jù)拷貝和內(nèi)存分配的開銷,從而提高網(wǎng)絡編程的性能和效率。
  • 高性能計算:Span<T> 可以用于訪問和操作大型數(shù)組或矩陣中的元素。通過使用 Span<T>,可以避免不必要的內(nèi)存分配和拷貝,提高計算速度和效率。

如何使用Span

在 .NET 中,可以通過以下幾種方式來創(chuàng)建 Span<T> 對象:

直接使用原始內(nèi)存指針

unsafe
{
    int[] array = { 1, 2, 3, 4 };
    fixed (int* ptr = array)
    {
        Span<int> span = new Span<int>(ptr, array.Length);
        // 對 span 進行操作
    }
}

在這個例子中,我們首先通過 fixed 關鍵字將 array 數(shù)組的地址固定下來,然后使用 new Span<int>(ptr, array.Length) 構造函數(shù)創(chuàng)建一個 Span<int> 對象,該對象引用了整個 array 數(shù)組。

使用數(shù)組

int[] array = { 1, 2, 3, 4 };
Span<int> span = new Span<int>(array);
// 對 span 進行操作

在這個例子中,我們直接使用 array 數(shù)組創(chuàng)建了一個 Span<int> 對象,該對象引用了整個數(shù)組。

使用數(shù)組的一部分

int[] array = { 1, 2, 3, 4 };
Span<int> span = new Span<int>(array, 1, 2);
// 對 span 進行操作

在這個例子中,我們使用 new Span<int>(array, 1, 2) 構造函數(shù)創(chuàng)建了一個 Span<int> 對象,該對象引用了 array 數(shù)組的第二個元素和第三個元素。

使用字符串

string str = "hello world";
Span<char> span = str.AsSpan();
// 對 span 進行操作

在這個例子中,我們使用 AsSpan 方法將一個字符串轉(zhuǎn)換為 Span<char> 對象,該對象引用了字符串的所有字符。

除了上述方式外,還可以使用 Memory<T> 或者 ReadOnlyMemory<T> 類型來創(chuàng)建 Span<T> 對象。Memory<T> 表示一個可變的內(nèi)存區(qū)域,而 ReadOnlyMemory<T> 表示一個不可變的內(nèi)存區(qū)域,它們都可以用來創(chuàng)建 Span<T> 對象。例如:

int[] array = { 1, 2, 3, 4 };
Memory<int> memory = new Memory<int>(array);
Span<int> span = memory.Span;
// 對 span 進行操作

在這個例子中,我們首先使用 new Memory<int>(array) 構造函數(shù)創(chuàng)建了一個 Memory<int> 對象,然后使用 Span 屬性獲取了其對應的 Span<int> 對象。

使用 Span<T> 可以避免數(shù)據(jù)拷貝和內(nèi)存分配的開銷,從而提高網(wǎng)絡編程的性能和效率。一般情況下,網(wǎng)絡數(shù)據(jù)包的二進制數(shù)據(jù)往往是連續(xù)存儲在內(nèi)存中的,Span<T> 可以直接引用該內(nèi)存塊,而不需要進行額外的拷貝操作。

Span在網(wǎng)絡編程中的應用

使用 Span<T> 解析網(wǎng)絡數(shù)據(jù)包的一般步驟:

  • 從網(wǎng)絡中接收到數(shù)據(jù):使用網(wǎng)絡編程庫(如Socket)接收網(wǎng)絡數(shù)據(jù),將數(shù)據(jù)存儲在一個字節(jié)數(shù)組或內(nèi)存緩沖區(qū)中。
  • 創(chuàng)建 Span<T> 對象:通過將字節(jié)數(shù)組或內(nèi)存緩沖區(qū)傳遞給 Span<T> 的構造函數(shù),創(chuàng)建一個 Span<T> 對象。例如:`Span<byte> dataSpan = new Span<byte>(dataBuffer);`
  • 解析數(shù)據(jù):利用 Span<T> 的索引和切片功能,可以方便地訪問和解析二進制數(shù)據(jù)。可以通過索引獲取特定位置的字節(jié),也可以使用切片操作獲取指定范圍的字節(jié)。例如:`byte firstByte = dataSpan[0];` 或 `Span<byte> headerSpan = dataSpan.Slice(0, headerLength);`
  • 處理數(shù)據(jù):根據(jù)具體的網(wǎng)絡協(xié)議,對二進制數(shù)據(jù)進行解析和處理,提取需要的信息。可以使用 Span<T> 提供的方法或自定義的處理邏輯進行操作。

Span和網(wǎng)絡編程的結合

`Span<T>` 在網(wǎng)絡編程中可以提供高性能的內(nèi)存訪問和數(shù)據(jù)處理,從而提升網(wǎng)絡應用程序的效率。下面是幾個使用 `Span<T>` 進行網(wǎng)絡編程的常見場景:

數(shù)據(jù)接收和解析:使用 `Socket` 接收到的字節(jié)數(shù)據(jù)可以直接轉(zhuǎn)換為 `Span<byte>`,避免了額外的內(nèi)存拷貝操作。然后,可以使用 `Span<T>` 提供的方法對數(shù)據(jù)進行解析,例如檢查數(shù)據(jù)包的長度、提取字段值等。

byte[] buffer = new byte[1024];

int bytesRead = socket.Receive(buffer); // 從 Socket 接收數(shù)據(jù)

Span<byte> data = buffer.AsSpan(0, bytesRead);

// 解析數(shù)據(jù)包...`

數(shù)據(jù)發(fā)送:使用 `Span<T>` 可以直接將數(shù)據(jù)發(fā)送到網(wǎng)絡中,而無需將數(shù)據(jù)復制到新的緩沖區(qū)中。這樣可以避免內(nèi)存拷貝的開銷,提高發(fā)送數(shù)據(jù)的效率。

byte[] data = GetPacketData(); // 獲取待發(fā)送的數(shù)據(jù)

socket.Send(data.AsSpan()); // 直接發(fā)送數(shù)據(jù)

數(shù)據(jù)處理和轉(zhuǎn)換:在網(wǎng)絡通信中,涉及到各種數(shù)據(jù)格式的轉(zhuǎn)換和處理操作。使用 `Span<T>` 可以方便地對字節(jié)數(shù)據(jù)進行解析、轉(zhuǎn)換和修改。

byte[] receivedData = ReceiveDataFromSocket(); // 從 Socket 接收數(shù)據(jù)

// 將接收到的數(shù)據(jù)轉(zhuǎn)換為字符串

string message = Encoding.UTF8.GetString(receivedData.AsSpan());

// 修改數(shù)據(jù)并發(fā)送回去

receivedData.AsSpan().Reverse(); // 反轉(zhuǎn)字節(jié)順序

SendDataToSocket(receivedData);`

緩沖區(qū)池化:在高并發(fā)的網(wǎng)絡應用程序中,使用緩沖區(qū)池化技術可以避免頻繁的內(nèi)存分配和釋放操作,提高性能。`Span<T>` 可以與緩沖區(qū)池化技術相結合,共享和重用緩沖區(qū),減少內(nèi)存開銷。

ArrayPool<byte> bufferPool = ArrayPool<byte>.Shared;

byte[] buffer = bufferPool.Rent(1024); // 從緩沖區(qū)池中租借一個緩沖區(qū)

int bytesRead = socket.Receive(buffer); // 從 Socket 接收數(shù)據(jù)

Span<byte> data = buffer.AsSpan(0, bytesRead);

// 處理接收到的數(shù)據(jù)...

bufferPool.Return(buffer); // 將緩沖區(qū)歸還給緩沖區(qū)池`

通過合理地利用 `Span<T>` 的特性和方法,我們可以在網(wǎng)絡編程中實現(xiàn)高效的數(shù)據(jù)處理和傳輸,提升網(wǎng)絡應用程序的性能和可伸縮性。但需要注意的是,使用 `Span<T>` 時要小心懸掛指針和內(nèi)存安全問題,確保操作的內(nèi)存是有效的并且不會被修改。

使用Socket和Span結合示例

使用 Socket 和 Span<T> 進行網(wǎng)絡數(shù)據(jù)包解析是一種高效、低內(nèi)存消耗的方式。下面是一個簡單的示例,演示如何使用這兩個類型進行網(wǎng)絡數(shù)據(jù)包解析:

// 假設已經(jīng)建立了一個 TCP 連接,并且從 Socket 接收到了一段字節(jié)數(shù)據(jù)

byte[] buffer = new byte[1024]; // 接收數(shù)據(jù)的緩沖區(qū)
int bytesRead = socket.Receive(buffer); // 從 Socket 接收數(shù)據(jù)

Span<byte> data = buffer.AsSpan(0, bytesRead); // 將接收到的字節(jié)數(shù)據(jù)轉(zhuǎn)換為 Span<byte>

// 解析數(shù)據(jù)包
while (data.Length > 0)
{
    // 檢查數(shù)據(jù)包的長度是否足夠
    if (data.Length < sizeof(int))
    {
        // 數(shù)據(jù)不完整,等待下一次接收
        break;
    }

    // 讀取數(shù)據(jù)包的長度
    int packetLength = BitConverter.ToInt32(data);
    
    // 檢查數(shù)據(jù)包是否完整
    if (data.Length < packetLength + sizeof(int))
    {
        // 數(shù)據(jù)不完整,等待下一次接收
        break;
    }
    
    // 提取數(shù)據(jù)包內(nèi)容
    Span<byte> packetData = data.Slice(sizeof(int), packetLength);

    // 處理數(shù)據(jù)包
    ProcessPacket(packetData);

    // 調(diào)整指針,繼續(xù)處理剩余數(shù)據(jù)
    data = data.Slice(sizeof(int) + packetLength);
}

在上面的示例中,我們首先從 Socket 接收數(shù)據(jù),并將接收到的字節(jié)數(shù)據(jù)存儲在一個字節(jié)數(shù)組中。然后,我們使用 AsSpan 方法將字節(jié)數(shù)組轉(zhuǎn)換為 Span<byte>,以便進行高效的數(shù)據(jù)包解析。

接下來,我們使用一個循環(huán)來處理數(shù)據(jù)包。在每次循環(huán)中,我們首先檢查是否有足夠的數(shù)據(jù)來讀取數(shù)據(jù)包的長度。如果數(shù)據(jù)不完整,我們等待下一次接收。如果有足夠的數(shù)據(jù),我們讀取數(shù)據(jù)包的長度,并檢查是否有足夠的數(shù)據(jù)來完整解析數(shù)據(jù)包。如果數(shù)據(jù)不完整,我們等待下一次接收。

一旦我們獲得了完整的數(shù)據(jù)包,我們可以使用 Slice 方法提取數(shù)據(jù)包的內(nèi)容,并進行相應的處理操作(例如解析數(shù)據(jù)、驗證數(shù)據(jù)、處理數(shù)據(jù)等)。

通過使用 Span<T> 和適當?shù)难h(huán)邏輯,我們可以高效地解析網(wǎng)絡數(shù)據(jù)包,減少內(nèi)存拷貝和數(shù)據(jù)處理的開銷,從而提高網(wǎng)絡應用程序的性能和效率。

責任編輯:姜華 來源: 今日頭條
相關推薦

2016-12-11 10:08:31

高性能組網(wǎng)能力

2020-11-06 18:51:17

LinuxTCP服務器

2023-11-01 11:51:08

Linux性能優(yōu)化

2018-03-08 12:17:38

大數(shù)據(jù)HPCHadoop

2023-11-01 11:59:13

2024-03-18 13:43:20

Linux架構

2023-12-13 10:22:04

APISpark數(shù)據(jù)

2013-11-08 10:12:07

2023-11-01 10:38:46

Linux高性能網(wǎng)絡編程

2018-08-14 11:05:25

2024-01-29 08:26:13

Span高性能數(shù)組數(shù)據(jù)結構

2020-02-06 13:40:35

編程緩存優(yōu)化

2024-04-01 10:07:47

應用程序數(shù)據(jù)數(shù)據(jù)庫

2018-10-08 15:22:36

IO模型

2023-12-18 11:21:40

MongoDB數(shù)據(jù)庫

2011-09-01 15:12:43

SQL ServerHadoop

2013-12-16 17:17:01

OpenMp數(shù)據(jù)處理

2010-01-21 16:12:28

NetFlow交換

2013-09-03 09:14:12

2023-11-01 11:27:10

Linux協(xié)程
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 不卡一区二区三区四区 | 成人av观看 | 国产精品高潮呻吟久久 | 日韩欧美国产综合 | 在线看免费的a | 国产一区二区日韩 | 精品日韩一区 | 黄色三级毛片 | 亚洲精品久久 | 精品一区二区三区在线观看 | 亚洲国产aⅴ成人精品无吗 综合国产在线 | 天天宗合网 | 色欧美综合 | 天天宗合网 | 国产 日韩 欧美 在线 | 中文字幕日本一区二区 | 国产一级电影在线观看 | 中文字幕一级 | 久久精品免费看 | 国产精品电影在线观看 | 久久久久久国产一区二区三区 | 久草a√| 一级a性色生活片久久毛片 午夜精品在线观看 | 日韩一区二区三区在线观看 | 91精品国产一区二区在线观看 | 欧美精品一区二区在线观看 | 久久99精品久久久 | 免费成人在线网站 | 欧美福利精品 | 日韩精品一区二区三区在线观看 | 99久久精品免费 | 国产亚洲精品精品国产亚洲综合 | 久久精品国产精品青草 | 日韩免费在线 | 欧美性受xxx| 91精品国产综合久久久久久蜜臀 | av男人的天堂av | 你懂的av | av免费观看在线 | 亚洲婷婷六月天 | 欧美在线国产精品 |