主頁 > .NET開發 > 【5min+】傳說中的孿生兄弟? Memory and Span

【5min+】傳說中的孿生兄弟? Memory and Span

2020-09-17 22:54:24 .NET開發

系列介紹

【五分鐘的dotnet】是一個利用您的碎片化時間來學習和豐富.net知識的博文系列,它所包含了.net體系中可能會涉及到的方方面面,比如C#的小細節,AspnetCore,微服務中的.net知識等等,
5min+不是超過5分鐘的意思,"+"是知識的增加,so,它是讓您花費5分鐘以下的時間來提升您的知識儲備量,

正文

在上一篇文章:《閃電光速拳? .NetCore 中的Span》 中我們提到了在.net core 2.x 所新增的一個型別:Span

它與咱們傳統使用的基礎型別相比具有超高的性能,原因是它減少了大量的記憶體分配和資料量復制,并且它所分配的資料記憶體是連續的,

但是您會發現它無法用在我們專案的某些地方,它獨特的 ref結構 使它沒有辦法跨執行緒使用、更沒有辦法使用Lambda運算式,

x

特別是在AspNetCore中,咱們會使用到大量的異步操作方法,“所以,這個時候如果我們又想跨執行緒操作資料又想獲得類似Span這樣的性能怎么辦呢?” 上一篇文章我們留下了這樣的一個問題,所以現在就是到了還愿的時候了,它就是與Span一起發布的孿生兄弟: Memory

x

獅子座和射手座黃金圣斗士同樣具備超越光速的能力

什么是Memory

那什么是Memory呢?不妨我們先來猜測一下,它的結構是什么樣子,畢竟它是Span的孿生兄弟,而Span的結構我們在前面就了解過了:

public readonly ref struct Span<T>
{
    public void Clear();
    public void CopyTo([NullableAttribute(new[] { 0, 1 })] Span<T> destination);
    public void Fill(T value);
    public Enumerator GetEnumerator();
    public Span<T> Slice(int start, int length);
    public T[] ToArray();
    public override string ToString();

    //.....
}

當時我們說Span有各種缺陷的原因是由于它獨特的 ref struct 關鍵字所導致的,導致它無法拆箱裝箱、無法書寫Lambda、無法跨執行緒等,但是它兄弟卻可以克服缺點,所以我們想想它會和Span在宣告上有哪些差距呢? 是的,您可能已經想到了:它不會有 ref 關鍵字了,

所以,我們看到它的內部結構就是醬紫的:

public readonly struct Memory<T>
{
    public static Memory<T> Empty { get; }
    public bool IsEmpty { get; }
    public int Length { get; }
    public Span<T> Span { get; }
    public void CopyTo([NullableAttribute(new[] { 0, 1 })] Memory<T> destination);
    public MemoryHandle Pin();
    public Memory<T> Slice(int start, int length);
    public T[] ToArray();
    public override string ToString();
}

和我們猜想的一樣,它少了ref關鍵字,內部方法也和Span差不多(同樣擁有CopyTo,Slice等),但是還是有一些差異,比如多了Pin方法,Span屬性等,

被宣告為ref struct的結構,叫做“ByRefLike”,所以在我們在進行反射的時候,我們使用Type會看到有這樣一個屬性:IsByRefLike

x

好像有點超綱了哈(>人<;)

按照MSDN給出的解釋:

該結構是使用中的C# ref struct 關鍵字宣告的, 不能將類似 byref 的結構的實體放置在托管堆上,

所以這也是為什么上一篇文章說的:Span只能放置在記憶體堆疊中的原因,

那么反過來想,沒有了ref關鍵字之后,Memory是不是就可以放置在托管堆上了呢?是不是就可以進行拆裝箱,克隆副本供其它執行緒的記憶體堆疊使用了呢? 好吧,可能是這樣,所以這也許就是它能夠被允許跨執行緒使用的原因吧,

進行到了這一步,那我們再回過頭來想想Memory是什么呢? 其實作在我們心里其實都已經有個底了:

與 Span<T>一樣,Memory<T> 表示記憶體的連續區域, 但 Span<T>不同,Memory<T> 不是ref 結構, 這意味著 Memory<T> 可以放置在托管堆上,而 Span<T> 不能, 因此,Memory<T> 結構與 Span<T> 實體沒有相同的限制, 具體而言:

  • 它可用作類中的欄位,
  • 它可跨 await 和 yield 邊界使用,

除了 Memory<T>之外,還可以使用 System.ReadOnlyMemory<T> 來表示不可變或只讀記憶體,

這是MSDN給出來的解釋,不是我亂編的哈??!(雖然和我們上面猜的一模一樣(●ˇ?ˇ●)

接下來,我們來看看他們到底有多像:

x

好吧,為了做該圖我已經使用了美工必殺器 - ps??

有沒有發現,除了名字之外,好像其它的都一模一樣??,甚至直接連注釋都懶得改了,

一樣卻又不一樣

既然作為孿生兄弟,必然有一些共通之處,而Memory作為對Span的增強(應該也算不算增強吧),那么內部的實作可能很多會與Span相似,

是的,查看Memory的源代碼您就會發現,它的內部某些方法就是通過Span來實作的:

public readonly struct Memory<T>
{
    public void CopyTo(Memory<T> destination) => Span.CopyTo(destination.Span);
    public T[] ToArray() => Span.ToArray();
}

有關Memory的源代碼,您可以點此查看:the source code of Memory,

所以您會發現Memory是可以直接轉換為Span的,但是Memory作為一個可以跨執行緒的型別被轉換為Span是相對危險的,所以Dotnet Core的開發人員直接在備注上寫了這樣的文字:

Such a cast can only be done with unsafe or marshaling code,in which case that's the dangerous operation performed by the dev, and we're just following suit here to make it work as best as possible.

意思就是這種轉換很危險,我來幫你做了算了,

x

如何使用

來吧,修改上面的Span會在Task中報錯的例子:

public async Task MemoryCanInLambda(Memory<string> buffer)
{
    await Task.Factory.StartNew(() =>
    {
        buffer.Trim("s");
    });
}

此時我們就可以在異步中使用Memory了,采用連續記憶體+指標級別的操作方案來操作資料內容,豈不爽歪歪?

異步的資料交由Memory,同步的資料交由Span,ForExample:


static async Task<int> ChecksumReadAsync(Memory<byte> buffer, Stream stream)
{
  int bytesRead = await stream.ReadAsync(buffer);
  return Checksum(buffer.Span.Slice(0, bytesRead));
  // Or buffer.Slice(0, bytesRead).Span
}
static int Checksum(Span<byte> buffer) { ... }

正是由于SpanMemory帶來的巨大性能優化,所以.NET Core的開發者們做了一件非常瘋狂的事:為.NET的庫添加了數百個多載方法, 比如,您現在可以看到我們經常使用的Int.Parse方法居然支持了Span,它的簽名是醬紫:

public static Int32 Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyles.Integer, [NullableAttribute(2)] IFormatProvider? provider = null);

除此之外,還有longdouble…………甚至連Guid和DateTime都有這樣的多載,
還有其它常用的各種類也開始支持以Span作為引數的多載方法了,比如Random、StringBuilder等,

public StringBuilder Append(ReadOnlySpan<char> value);

先不談重建這些基礎常用型別的多載作業量有多大,我們應該想想.NET為什么要這么做呢?就是為了我們能夠使用SpanMemory來代替我們現有的一些操作,從而提升性能,

那么僅僅是開發底層框架才適合用它們嗎? 當然不是,就好比是截取字串的操作,無論是底層框架還是應用程式級別的代碼都會用到,所以如果有可能,而當我們的專案又正好是.netCore 2.x以上的版本,為何不去嘗試使用下呢?

不要因為“我知道Span不過就是把原有的某某操作放到記憶體某處,不過如此”,就對它產生偏見,確實,Span的實作很簡單,您如果有興趣可以查看它的實作代碼,.net core正在為它的實作和使用做巨大的適配作業,C# 從7.x 開始就不斷對異步操作和記憶體分配進行優化,這或許也為我們未來.NET的發展給了一點點提示,加油,偉大的開發人員們,(? ?_?)?

最后,小聲說一句:創作不易,點個推薦吧??

x

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/69017.html

標籤:.NET Core

上一篇:定時器_在.net core3.0 webapi中添加自定義定時器功能

下一篇:C#_.net core 3.0自定義讀取.csv檔案資料_解決首行不是標題的問題_Linqtocsv改進

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more