過年啦,寫個短點的,同時,提前給大家拜個年,
?
總有小伙伴們跑過來討論關于Span和Memory的使用,眼瞅是最近關于Span的文章有點多,看飛了,
今天寫這個,就是往回拉一拉,
寫之前,先宣告一下,這些內容是我自己使用的一些經驗,并不代表這些類的全部內容就是這些,只是說,我是這么用的,而且用得很好,
1. Span
Span在我的概念中,就是一個快速的同步訪問器,
就這么簡單,
Span很快,在我前邊關于Span的文章中分析過,可以移步【傳送門】去看,而且,它與foreach一起使用也很快,主要是因為Span的GetEnumerator使用了參考回傳,
你看,Span本身就被設計成了一個非常快的東西,
同時,Span是同步的,也就是說,它沒有提供任何異步的方法和屬性,
說到為什么Span是同步的,這倒是一個問題,我們需要從根上來找找,Span背后的連續記憶體塊,主要來自于以下幾個方面:
- 陣列的切片
Memory<T>- 非托管指標
void* stackalloc
其中,第一個是堆上分配的陣列的一部分,第二個是基于連續記憶體的,第三個非托管void*本身就是同步的,
第四個單獨說一下,stackalloc提供的是在執行緒的堆疊上分配記憶體,如果Span可以使用異步,會導致一個執行緒可以訪問另一個執行緒的堆疊,顯然這是不安全和不合理的,所以,保持Span同步是必須的,
所以,Span就是一個性能非常好的,針對連續記憶體的同步訪問器,
2. Memory
Memory,就是一個實際的記憶體塊,
與Span不同,Memory可以在異步流中使用,同時,它還提供了獲取同步訪問器的方法Memory<T>.Span(),
Memory可以有多種來源,例如:
- 陣列切片
MemoryMarshal的各種Create方法,例如MemoryMarshal.CreateFromPinnedArray()這樣的,
第一個是最基本的用法,從陣列T[]中取一個切片成為Memory,
第二個方法會復雜一些,用了一個特殊的方法來創建Memory,像上邊的例子,CreateFromPinnedArray用了一個已經固定的陣列,在Dotnet中,可以通過固定一個物件,來禁止GC移動物件,這在將Memory傳遞給非托管物件時非常有用,
總之,Memory就是一個實際的記憶體塊,這個記憶體塊可以被用到任何地方,并可以使用它的同步訪問器Span進行訪問,
3. ReadOnlyX
印象中有三種:ReadOnlySpan、ReadOnlyMemory、ReadOnlySequence,
沒什么特別的,就是ReadOnly,只讀啦,
前兩個,ReadOnlySpan、ReadOnlyMemory,就是Span和Memory對應的只讀物件,
4. ReadOnlySequence
ReadOnlySequence也不算復雜,就是一個ReadOnlyMemory元素的序列,
基于作業系統的記憶體管理,有時候Memory不是連續的,可能會分片段,所以就需要有個結構來表示一個Memory鏈/Memory串列類似的序列,這是ReadOnlySequence的由來,而它本身也是一個ReadOnlyMemory的串列,
同時,它也提供了一些屬性來優化序列中包含一個元素的情況:
- IsSingleSegment,用來快速檢查是否只包含一個記憶體項
- FirstSpan,該速訪問ReadOnlySpan訪問器的第一個記憶體項
因此雖然被定義為序列,但處理單個元素,例如單個Span或Memory也容易很多,
?
這就是今天的全部內容了,
有沒有跟你用的不一樣?
?
文章最后,再次祝大家牛年大吉,萬事勝意~
?
![]() |
微信公眾號:老王Plus 掃描二維碼,關注個人公眾號,可以第一時間得到最新的個人文章和內容推送 本文著作權歸作者所有,轉載請保留此宣告和原文鏈接 |
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/258593.html
標籤:.NET Core
上一篇:c#記兩個變數進行值交換

