C#9.0 終於來了,帶你一起解讀 nint 和 Pattern matching 兩大新特性玩法

一:背景

1. 講故事

上一篇跟大家聊到了Target-typed newLambda discard parameters,看博客園和公號里的閱讀量都達到了新高,甚是欣慰,不管大家對新特性是多頭還是空頭,起碼還是對它抱有一種極為關注的態度,所以我的這個系列還得跟,那就繼續開擼吧,今天繼續帶來兩個新特性,更多新特性列表,請大家關注:新特性預覽

二:新特性研究

1. Native ints

從字面上看貌似是什麼原生類型ints,有點莫名其妙,還是看一看Issues上舉得例子吧:


Summary: nint i = 1; and nuint i2 = 2;

Shipped in preview in 16.7p1.

有點意思,還是第一次看到有nint這麼個東西,應該就是C#9新增的關鍵詞,好奇心爆棚,快來實操一下。


   static void Main(string[] args)
   {
        nint i = 10;
        Console.WriteLine($"i={i}");
   }

從圖中看,可以原樣輸出,然後用ILSpy查查底層IL代碼,發現連IL代碼都不用看。如下圖:

從圖中看原來 nint 就是 IntPtr 結構體哈,如果你玩過 C# 到 C++ 之間的互操作,我相信你會對Ptr再熟悉不過了,從這個 nint 上看,你不覺得C#團隊對指針操作是前所未有的重視嗎? 前有指針類型IntPtr,後有內存段處理集合Span,到現在直接提供關鍵詞支持,就是盡最大努力讓你在類型安全的前提下使用指針。

這就讓我想起了前些天寫的一篇互操作的文章,現在就可以用nint進行簡化了,來段代碼給大家看一下。

  • 原來的寫法:

        [DllImport("ConsoleApplication1.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
        extern static IntPtr AddPerson(Person person);

        static void Main(string[] args)
        {
            var person = new Person() { username = "dotnetfly", password = "123456" };
            var ptr = AddPerson(person);
            var str = Marshal.PtrToStringAnsi(ptr);
        }

  • IntPtr -> nint 的寫法

總的來說這個關鍵詞不是最重要的,重要的是C#團隊對指針操作抱有前所未有的重視,這是一個非常积極的信號。

2. Pattern matching improvements

模式匹配這個不算是什麼新特性了,在本次C#9中也是繼續得到了完善,可能有很多朋友對模式匹配不是很熟悉,畢竟是C#7才有的新玩法,後面幾乎每一個新版本都在跟蹤完善,我先科普一下吧。

模式匹配到底解決了什麼問題

大家在編碼的過程中,不可能遇不到 if/else 嵌套 if/else 的這種情況,有時候嵌套甚至達到5,6層之多,特別影響代碼可讀性,我就來YY個例子。

現在各個地方都在發不同面值的消費券,為了實現千人千面,消費券的發放規則如下:

性別 年齡 地區 面值
<20 安徽 2000
<40 上海 4000
剩餘 剩餘 3000
<20 安徽 2500
<60 安徽 1500

如果用傳統的方式,你肯定要用各種花哨的if/else來實現,如下代碼:


        static decimal GetTicket(string sex, int age, string area)
        {
            if (sex == "男")
            {
                if (age < 20 && area == "安徽")
                {
                    return 2000;
                }
                else
                {
                    if (age < 40 && area == "上海")
                    {
                        return 4000;
                    }
                    else
                    {
                        return 3000;
                    }
                }
            }
            else
            {
                if (age < 20 && area == "安徽")
                {
                    return 2500;
                }
                if (age < 60 && area == "安徽")
                {
                    return 1500;
                }
            }

            return 0;
        }

這種代碼可讀性不是一般的差,就像大強子說的那樣:看着都想打人。。。 問題來了,這代碼還有救嗎??? 當然有了,這就需要用Pattern matching 去簡化,畢竟它就是為了這種問題而生的,修改后的代碼如下:


        static decimal GetTicket_Pattern(string sex, int age, string area)
        {
            return (sex, age, area) switch
            {
                ("男", < 20, "安徽") => 2000,
                ("男", < 40, "上海") => 4000,
                ("男", _, _) => 3000,
                ("女", < 20, "安徽") => 2500,
                ("女", < 60, "安徽") => 1500,
                _ => 0
            };
        }

看到這種化簡后的代碼是不是非常驚訝,這就是 Pattern matching 要幫你解決的場景,接下來看看底層的IL代碼是什麼樣子。

從圖中看,這反編譯后的代碼比我手工寫的還要爛,無力吐槽哈,當然 模式匹配 有各種千奇百怪的玩法,絕對讓你瞠目結舌,更多玩法可參考官方文檔:模式匹配

這個特性最重要的是你一定要明白它的客戶群在哪裡?

三: 總結

總的來說,這兩個特性都是比較實用的,尤其是 Pattern matching 化解了你多少不得不這麼寫的爛代碼,頭髮護理就靠它了,快來給它點個贊吧!

好了,先就這樣吧,感謝您的閱讀,希望本篇對你有幫助,謝謝。

如您有更多問題與我互動,掃描下方進來吧~

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

虎鯨生氣了!多艘船隻罕見遭圍攻損壞 科學家憂環境破壞

摘錄自2020年9月14日自由時報報導

過去兩個月來虎鯨開始攻擊船隻,造成嚴重損害,科學家認為,這可能與虎鯨的生存壓力有關。

《衛報》報導,據傳虎鯨騷擾航行西班牙與葡萄牙之間的船隻,讓科學家感到困惑,過去兩個月,多艘船隻發出求救訊息,至少有一艘船因為嚴重損壞回港。船員莫里斯(Victoria Morris)表示,他所在的船隻被9頭虎鯨包圍,這些重達6噸的虎鯨不斷撞擊船隻達一小時,導致船隻轉了180度,發動機也關閉,同時虎鯨們還發出巨大的「口哨聲」。

報導表示,科學家指出虎鯨是高度群聚且好奇的動物,跟隨小船並嬉戲不是太罕見的事,但這件事奇怪的地方在於,虎鯨表現出侵略性,一般而言牠們不太會蓄意攻擊。科學家認為,這可能代表直布羅陀海峽的虎鯨有巨大的生存壓力,牠們要與漁船爭搶食物,且繁忙的航線對環境造成破壞,當地的虎鯨已經瀕臨滅絕,只剩下大約30頭成體。

海洋
國際新聞
虎鯨

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

北極最大冰架裂解!格陵蘭冰川110平方公里大冰塊脫離

摘錄自2020年9月14日聯合報報導

英國廣播公司(BBC)報導,衛星畫面顯示,北極剩餘的最大冰架、位於格陵蘭東北部的79N冰川有一大塊脫離,脫離的面積大約有110平方公里,已碎成許多較小的冰塊。

德國埃朗恩 – 紐倫堡大學的極地研究員珍妮.特頓(Jenny Turton)表示:「自1980年以來,此地區的大氣層溫度上升大約攝氏3度。而在2019年到2020年間,這裡夏天的氣溫創新高。」79N冰川大約有80公里長,20公里寬,是格陵蘭東北冰流(Northeast Greenland Ice Stream)漂流的前端,從陸地流到海裡,成為浮冰。

而在79N冰川的前沿,分成兩條冰川,較小的支流往北走,這條支流稱為史帕特冰川(Spalte Glacier),而現在出現裂解的正是這條冰川。史帕特冰川2019年已出現嚴重裂縫,今年夏天的高溫成為致命一擊,現在史帕特冰川已成為冰山的浮冰。

氣候變遷
國際新聞
北極
冰川融化
冰架
全球暖化

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

不到20萬的寶馬,車主們都說開起來很爽!

8百公里油耗(L):5。5/6。2/6。4車主百公里油耗(L):8。41/8。62驅動方式:前置前驅底盤懸挂:前麥弗遜/后多連桿式前排腿部空間(mm):890-1135前排高度(mm):940前排寬度(mm):1460後排腿部空間(mm):550-800後排高度(mm):900後排寬度(mm):1420實際體驗(體驗者178cm):前排頭部1拳/後排頭部4指/後排腿部1拳4指。

身為國內售價最接地氣的寶馬車型,寶馬1系三廂車型把定價下探到20萬元左右,它既能與奧迪A3展開競爭,也給寶馬的潛在用戶們提供了一個新選擇。

寶馬1系三廂車型採用了UKL前驅平台進行打造,並且搭載了B38系列1.5T發動機和分為高低功率調校的B48系列2.0T發動機,在傳動方面則採用來自愛信的6AT/8AT變速箱。

寶馬1系採用前驅的形式,雖然在駕駛感受上比以往的寶馬車型有所減弱,但它更易於控制,成本也得以下降。現在已經在使用這款車型的車主們對它有什麼評價?下面我們就來詳細看看。

長寬高:4456*1803*1448mm

軸距:2670mm

定位:緊湊型車

寶馬1系三廂的前臉采經典的“雙腎”造型中網,格柵造型的比較圓潤攻擊性不算十分突出。頭燈內帶有多邊形天使眼設計,並且大燈輪廓明顯向後延伸。稍有遺憾的是大燈沒有採用開眼角式設計,而側面輪廓緊湊而協調,短促的車尾造型提升了整車的運動感!

在內飾方面,它的布局分明清晰,中控台上部採用軟質材料覆蓋並且帶有縫線裝飾,中部配有高亮鋼琴烤漆面板,整體時尚感較好而且內飾的做工細緻、質感頗為優良!車門內襯也採用皮革和搪塑工藝材質包裹,整體質感良好。

發動機:1.5T/2.0T

最大馬力(pS):136/192/231

最大扭矩(Nm):220/280/350

變速箱:6AT/8AT

百公里加速(s):9.4/7.5/6.8

百公里油耗(L):5.5/6.2/6.4

車主百公里油耗(L):8.41/8.62

驅動方式:前置前驅

底盤懸挂:前麥弗遜/后多連桿式

前排腿部空間(mm):890-1135

前排高度(mm):940

前排寬度(mm):1460

後排腿部空間(mm):550-800

後排高度(mm):900

後排寬度(mm):1420

實際體驗(體驗者178cm):前排頭部1拳/後排頭部4指/後排腿部1拳4指。

感興趣的朋友可以點擊小程序查看詳細口碑,從口碑中可以看到,車主們對這款車型的操控感受,油耗控制能力和動力輸出比較滿意!而對於發動機NVH控制,一些配置的缺失有一些意見……

咱們發現寶馬1系的優惠還是比較大的,在廣州、武漢等地一般需要的搭配店內貸款、上保險、加裝飾等消費項目。

寶馬1系三廂車型在乘坐空間和內飾質感方面表現比較優良,是一款比較適合家用的車型,只是1.5T發動機採用直列3缸的設計結構,目前國內消費者對於這樣的發動機形式的接受度仍不算高。它的2.0T車型動力表現很強勁,只是售價門檻比較高。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

動力一樣還更大更便宜,這車銷量卻不到POLO的1/10

說實話,追求大大大空間的人就別買小型車啊。而我就是覺得空間不那麼重要,平日都是一個人用車居多的,後排很少用來載人的。所以後排空間小一點對我來說影響不大。一句話:一兩個人用車就挺好的。晶銳車主:其他地方,我都可以原諒pOLO,但是安全配置方面,真的讓我對pOLO下不了手啊。

大眾pOLO可以說是國內賣得最好的小型兩廂車

但是同胞兄弟晶銳的銷量則可以用慘淡來形容

簡直就是連pOLO的零頭都不如

明明技術平台、空間表現、性能等硬性指標都差別不大

那為什麼銷量卻是一個天堂一個地獄呢?

我們來看看車主們怎麼說吧!

晶銳車主:選擇晶銳之前我也考慮過pOLO(因為太多人買了,自然會考慮一下),但是pOLO的外觀令我覺得太乏味了。而相比之下,晶銳就顯得個性多了,雙色車身,車身線條很剛勁,還有繽紛車身色彩,看上去活力十足,非常適合年輕人。

pOLO車主:我想,購買大眾pOLO的車主絕大多數都是年輕人,而且很多都是過着平淡生活的年輕人。那麼pOLO就非常適合我這類人。pOLO整體看上去很飽滿,甚至看久了還會覺得挺精美的。反正,沒有人會覺得它有多突出,但也沒有人會將它歸入丑的那一類。

一句話:普通人總比個性主義者多。

晶銳車主:雖然晶銳的內飾用料一般、布局很常規,不過這些我都不在乎。價格就擺在這裏了,並不能奢求太多,用起來順手就好了。我更看中的是晶銳的內飾有拼色處理,不會像pOLO那黑黑的內飾那麼壓抑。

pOLO車主:我知道黑色顯小、黑色壓抑,但是黑色也百搭啊!我家的pOLO就是內飾全黑的;中控台是全黑的,但功能區劃分明確,實體按鍵操作便捷,平時開車盲操作也沒問題;座椅也是全黑的,用久了就知道很耐臟。反正,我覺得pOLO就是非常實在的存在。

一句話:反正都是簡潔實用為主。

晶銳車主:雖然軸距是一樣的,但是外觀尺寸,晶銳還是比pOLO大那麼一點。而且其實車內的頭部空間和腿部空間都是說得過去的。

pOLO車主:說話為什麼不能實在一點呢?說實話,追求大大大空間的人就別買小型車啊。而我就是覺得空間不那麼重要,平日都是一個人用車居多的,後排很少用來載人的。所以後排空間小一點對我來說影響不大。

一句話:一兩個人用車就挺好的。

晶銳車主:其他地方,我都可以原諒pOLO,但是安全配置方面,真的讓我對pOLO下不了手啊。

pOLO車主:在安全配置方面,pOLO可能做得不夠全面,但其他方面的配置pOLO給得也不少啊;要想比較豐富的配置可以選pOLO的頂配車型啊。

一句話:算了吧,其實兩款車的配置都算不上厚道啊。

晶銳車主:嗯,這方面可以說跟pOLO一模一樣的。靠譜!

pOLO車主:晶銳還挺喜歡用“與pOLO一樣的動力系統”來蹭熱度的。但別忘了還有pOLO GTI哦,那是1.4T發動機。還有,在調校、科技含量等方面,都是有些不一樣的啊。

一句話:兩款車也就都是日常夠用吧。

晶銳車主:晶銳的價格本身就比pOLO低一點點,優惠也有個7、8千。買下來還是挺划算的。

pOLO車主:pOLO的指導價是會比晶銳貴一點,但優惠基本是以萬為單位的呀。算下來,最後的成交價分分鐘比晶銳要低呢~

一句話:在不少地方,pOLO的價格算下來更便宜。

說到底啊,晶銳相比於pOLO來說是有它的個性所在的,而且指導價看上去是相對低一點點。但是!小編認為,晶銳的銷量會大不如pOLO的原因主要在於品牌效應的問題。兩者品牌定位的不同,晶銳的配置更低,而且用料上也更显示出廉價感,這樣子就進一步拉低了產品形象和銷量咯~

本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

動手造輪子:實現一個簡單的 AOP 框架

動手造輪子:實現一個簡單的 AOP 框架

Intro

最近實現了一個 AOP 框架 — FluentAspects,API 基本穩定了,寫篇文章分享一下這個 AOP 框架的設計。

整體設計

概覽

IProxyTypeFactory

用來生成代理類型,默認提供了基於 Emit 動態代理的實現,基於接口設計,可以擴展為其他實現方式

接口定義如下:

public interface IProxyTypeFactory
{
    Type CreateProxyType(Type serviceType);

    Type CreateProxyType(Type serviceType, Type implementType);
}

IProxyFactory

用來生成代理實例,默認實現是基於 IProxyTypeFactory 生成代理類型之後創建實例

接口定義如下:

public interface IProxyFactory
{
    object CreateProxy(Type serviceType, object[] arguments);

    object CreateProxy(Type serviceType, Type implementType, params object[] arguments);

    object CreateProxyWithTarget(Type serviceType, object implement, object[] arguments);
}

IInvocation

執行上下文,默認實現就是方法執行的上下文,包含了代理方法信息、被代理的方法信息、方法參數,返回值以及用來自定義擴展的一個 Properties 屬性

public interface IInvocation
{
    MethodInfo ProxyMethod { get; }

    object ProxyTarget { get; }

    MethodInfo Method { get; }

    object Target { get; }

    object[] Arguments { get; }

    Type[] GenericArguments { get; }

    object ReturnValue { get; set; }

    Dictionary<string, object> Properties { get; }
}

IInterceptor

攔截器,用來定義公用的處理邏輯,方法攔截處理方法

接口定義如下:

public interface IInterceptor
{
    Task Invoke(IInvocation invocation, Func<Task> next);
}

invocation 是方法執行的上下文,next 代表後續的邏輯處理,類似於 asp.net core 里的 next ,如果不想執行方面的方法不執行 next 邏輯即可

IInterceptorResolver

用來根據當前的執行上下文獲取到要執行的攔截器,默認是基於 FluentAPI 的實現,但是如果你特別想用基於 Attribute 的也是可以的,默認提供了一個 AttributeInterceotorResovler,你也可以自定義一個適合自己的 InterceptorResolver

public interface IInterceptorResolver
{
    IReadOnlyList<IInterceptor> ResolveInterceptors(IInvocation invocation);
}

IInvocationEnricher

上面 IInvocation 的定義中有一個用於擴展的 Properties,這個 enricher 主要就是基於 Properties 來豐富執行上下文信息的,比如說記錄 TraceId 等請求鏈路追蹤數據,構建方法執行鏈路等

public interface IEnricher<in TContext>
{
    void Enrich(TContext context);
}
public interface IInvocationEnricher : IEnricher<IInvocation>
{
}

AspectDelegate

AspectDelegate 是用來將構建要執行的代理方法的方法體的,首先執行註冊的 InvocationEnricher,豐富上下文信息,然後根據執行上下文獲取要執行的攔截器,構建一個執行委託,生成委託使用了之前分享過的 PipelineBuilder 構建中間件模式的攔截器,執行攔截器邏輯

// apply enrichers
foreach (var enricher in FluentAspects.AspectOptions.Enrichers)
{
    try
    {
        enricher.Enrich(invocation);
    }
    catch (Exception ex)
    {
        InvokeHelper.OnInvokeException?.Invoke(ex);
    }
}

// get delegate
var builder = PipelineBuilder.CreateAsync(completeFunc);
foreach (var interceptor in interceptors)
{
    builder.Use(interceptor.Invoke);
}
return builder.Build();

更多信息可以參考源碼: https://github.com/WeihanLi/WeihanLi.Common/blob/dev/src/WeihanLi.Common/Aspect/AspectDelegate.cs

使用示例

推薦和依賴注入結合使用,主要分為以微軟的注入框架為例,有兩種使用方式,一種是手動註冊代理服務,一種是自動批量註冊代理服務,來看下面的實例就明白了

手動註冊代理服務

使用方式一,手動註冊代理服務:

為了方便使用,提供了一些 AddProxy 的擴展方法:

IServiceCollection services = new ServiceCollection();
services.AddFluentAspects(options =>
    {
        // 註冊攔截器配置
        options.NoInterceptProperty<IFly>(f => f.Name);

        options.InterceptAll()
            .With<LogInterceptor>()
            ;
        options.InterceptMethod<DbContext>(x => x.Name == nameof(DbContext.SaveChanges)
                                                || x.Name == nameof(DbContext.SaveChangesAsync))
            .With<DbContextSaveInterceptor>()
            ;
        options.InterceptMethod<IFly>(f => f.Fly())
            .With<LogInterceptor>();
        options.InterceptType<IFly>()
            .With<LogInterceptor>();

        // 註冊 InvocationEnricher
        options
            .WithProperty("TraceId", "121212")
            ;
    });
// 使用 Castle 生成代理
services.AddFluentAspects(options =>
    {
        // 註冊攔截器配置
        options.NoInterceptProperty<IFly>(f => f.Name);

        options.InterceptAll()
            .With<LogInterceptor>()
            ;
        options.InterceptMethod<DbContext>(x => x.Name == nameof(DbContext.SaveChanges)
                                                || x.Name == nameof(DbContext.SaveChangesAsync))
            .With<DbContextSaveInterceptor>()
            ;
        options.InterceptMethod<IFly>(f => f.Fly())
            .With<LogInterceptor>();
        options.InterceptType<IFly>()
            .With<LogInterceptor>();

        // 註冊 InvocationEnricher
        options
            .WithProperty("TraceId", "121212")
            ;
    }, builder => builder.UseCastle());

services.AddTransientProxy<IFly, MonkeyKing>();
services.AddSingletonProxy<IEventBus, EventBus>();
services.AddDbContext<TestDbContext>(options =>
{
    options.UseInMemoryDatabase("Test");
});
services.AddScopedProxy<TestDbContext>();

var serviceProvider = services.BuildServiceProvider();

批量自動註冊代理服務

使用方式二,批量自動註冊代理服務:

IServiceCollection services = new ServiceCollection();
services.AddTransient<IFly, MonkeyKing>();
services.AddSingleton<IEventBus, EventBus>();
services.AddDbContext<TestDbContext>(options =>
{
    options.UseInMemoryDatabase("Test");
});

var serviceProvider = services.BuildFluentAspectsProvider(options =>
            {
                options.InterceptAll()
                    .With<TestOutputInterceptor>(output);
            });

// 使用 Castle 來生成代理
var serviceProvider = services.BuildFluentAspectsProvider(options =>
            {
                options.InterceptAll()
                    .With<TestOutputInterceptor>(output);
            }, builder => builder.UseCastle());

// 忽略命名空間為 Microsoft/System 的服務類型
var serviceProvider = services.BuildFluentAspectsProvider(options =>
            {
                options.InterceptAll()
                    .With<TestOutputInterceptor>(output);
            }, builder => builder.UseCastle(), t=> t.Namespace != null && (t.Namespace.StartWith("Microsft") ||t.Namespace.StartWith("Microsft")));

More

上面的兩種方式個人比較推薦使用第一種方式,需要攔截什麼就註冊什麼代理服務,自動註冊可能會生成很多不必要的代理服務,個人還是比較喜歡按需註冊的方式,更為可控。

這個框架還不是很完善,有一些地方還是需要優化的,目前還是在我自己的類庫中,因為我的類庫里要支持 net45,所以有一些不好的設計改起來不太方便,打算遷移出來作為一個單獨的組件,直接基於 netstandard2.0/netstandard2.1, 甩掉 netfx 的包袱。

Reference

  • https://github.com/WeihanLi/WeihanLi.Common/blob/dev/src/WeihanLi.Common/Aspect
  • https://www.cnblogs.com/weihanli/p/12700006.html

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

讀懂操作系統之虛擬內存TLB與緩存(cache)關係篇(四)

前言

前面我們講到通過TLB緩存頁表加快地址翻譯,通過上一節緩存原理的講解為本節做鋪墊引入TLB和緩存的關係,同時我們來完整梳理下從CPU產生虛擬地址最終映射為物理地址獲取數據的整個過程是怎樣的,若有錯誤之處,還請批評指正。

TLB和緩存串行訪問(Serial TLB & Cache Access)

這裡會跳過前面對虛擬頁號、虛擬頁偏移量、TLB索引和標記等的詳細分析和計算,不清楚的童鞋請先查看前面文章再來看本文。假設我們有14位的虛擬地址、12位的物理地址,每頁大小為64字節,如下:

 

 

同時假設已完全清楚虛擬地址和物理地址劃分,接下來則是針對虛擬地址和物理地址進行位劃分,如下:

同時我們假設TLB是通過組相聯來進行映射,TLB中有16個條目,4路相聯,所以TLB索引(TI)和TLB標記(TT)在虛擬地址中虛擬頁號進行位劃分如下: 

 

我們假設緩存採取直接映射的機制,緩存大小為64字節,每塊大小為4個字節,說明緩存有16塊即4位,位偏移為2位,所以緩存索引(CI)和緩存標記(CT)在物理地址中進行位劃分如下:

現假設讀取虛擬地址(0x0255),那麼將其劃分為VPN(0x09),VPO(0x15),然後將VPN劃分為TT(0x02)和TI(1)如下:

接下來通過TT(0x02)和TI(1)去查找TLB,如下:

此時我們會發現TLB缺失,緊接着通過VPN(0x0916 = 2110)去頁表中查找得到PPN(0x1716 = 2310),如下: 

 

因其PPO = VPO(0x15),所以計算出物理地址為(23 * 64+21 = 149310 = 0x5D516

然後根據上述物理地址劃分為CT(0x17)、CI(5)、CO(1),如下:

最後通過上述CT(0x17)和CI(5)去查找緩存,此時緩存命中,然後將數據發送到CPU,如下:

從CPU到獲取數據整個的過程是這樣的:【1】CPU產生虛擬地址【2】TLB翻譯成物理地址【3】TLB命中,將物理地址發送到緩存【4】緩存命中返回數據。其中每一個過程涉及到的細節,比如TLB缺失、頁缺失等等前面已有詳細講解,殊途同歸,大致過程則是如下圖解

通過如上可看出此時TLB與Cache是串行訪問的關係,這是最簡單同時也是比較慢的方式,因為不得不等待TLB翻譯完成后才去檢查緩存中是否有數據,如此一來將對CPU處理速度產生重大影響,涉及到大量內存訪問時間。

TLB和緩存并行訪問(Parallel TLB & Cache Access)

當前處理器最普遍的設計是採取TLB和Cache并行的方式,有些也稱之為重疊訪問(Overlapping TLB & Cache Access),從而提高訪問速度,那麼并行訪問到底是如何做的呢?有沒有什麼使用限制呢?這裏我們以Intel Skylake(英特爾第六代微處理器架構)為例來說明,其虛擬地址和物理地址結構大致如下:

看到上述結構我們可以發現物理地址中的PPN和緩存標記(CT)位數相等以及其他,英特爾這樣設計就是為了讓TLB和Cache可以并行訪問。TLB和Cache并行訪問原理:虛擬地址(VA)中的高階位即(VPN)用來查找TLB,而低階位(VPO)用來查找緩存。通過TLB將VPN映射到PPN,此時PPN作為緩存標記(CT),而將VPO中的低階位作為緩存偏移量(CO),高階位作為緩存索引(CI)。有了緩存標記和緩存索引我們就可以查詢到數據,比如CPU產生虛擬地址(0x7916 = 00011110012),此時通過并行訪問則為如下圖解

我們結合上述圖解繼續進行分析將并行訪問分為三種情況,比如上緩存中的tag = 11,同時我們產生的PPN = tag = 11,說明緩存標記等於物理頁號,同時緩存命中,最終返回數據B5給CPU(其一)。假設產生的緩存標記不是11,那麼說明緩存標記不等於頁號或者緩存缺失,但此時TLB命中,那麼將通過TLB中的物理頁號直接訪問主存(其二)。否則做標準的虛擬地址翻譯(其三)。為便於大家理解,我們通過偽代碼形式來說明:

if (cache hit && cache tag = PPN)
  //返回數據到CPU
else if (cache miss || cache tag != PPN && TLB hit) 
  //通過TLB中的PPN訪問主存
else
  //標準地址翻譯

兩種緩存架構(Cache & TLB Access)

緩存索引(Cache index)用於查找數據在緩存中的索引位置,而緩存標記(Cache tag)則是驗證緩存中有哪些數據。從上述對并行訪問原理講解我們知道將虛擬地址中的虛擬偏移量可作為物理緩存索引,這裏我們稱之為虛擬索引,同時我們將VPN轉換為PPN,這種模式稱之為虛擬索引、物理標記緩存架構(Virtual-indexed Physically-tagged Caches),其實我們也可以將虛擬地址中的偏移量作為緩存標記,也就是說虛擬地址中的偏移量(VPO)既作為緩存索引也作為緩存標記,這種緩存架構成為虛擬索引、虛擬標記緩存架構(Virtual-indexed Virtually-tagged Caches),也叫虛擬地址緩存(Virtual Address Caches),接下來我們來分析這兩種緩存架構。

虛擬索引、虛擬標記緩存(Virtual-indexed Virtually-tagged Caches)

 

 

此種緩存架構讓緩存保存虛擬地址,但是現代處理器極少使用這種緩存設計,雖然很塊,但是處理起來很複雜, 比如進行上下文切換時需要刷新緩存(當然可以在地址空間添加ASID),但是即使這樣,由於頁面可以共享而造成處理頁面別名問題,用於直接映射緩存的解決方案,共享頁面的VA必須在緩存索引位中一致,確保訪問同一PA的所有VA將在直接映射的緩存(早期SPARC)中發生衝突,所以大多處理器採用第二種(VA-PA)緩存架構。

虛擬索引、物理標記緩存(Virtual-indexed Physically-tagged Caches)

 

并行TLB & Cache訪問採取的就是此種架構,此種架構要求緩存索引完全包含在虛擬地址中的虛擬偏移量中。緩存標記和PPN相等(當然第一種)當查詢緩存時也執行TLB訪問,它是當前處理器最常見的設計,我們知道緩存使用的是物理地址,而CPU產生的是虛擬地址,這也就意味着沒有TLB就無法完成緩存查找。前面我們了解到緩存數據存儲結構存在直接映射、組相聯、全相聯三種結構,在此種緩存架構中有使用限制,我們首先來看看直接映射。

 

并行訪問的本質在於緩存查詢數據無需等待TLB完成,二者可同時開始,所以當兩者訪問完成后需要進行比較,如果(cache size <=  page size)即(C = L + b) <= P才有效,因為對於緩存的所有輸入都無需進行任何翻譯。

通過組相聯增加了緩存的關聯性從而減少索引到緩存所需地址的位數,在訪問完成後進行比較,如果(cache size) / (associativity) ≤ page size即(C <= P + A)才有效。對於緩存和TLB都採用的組相聯從而減少缺失率,所以對於并行訪問中的緩存組相聯映射必須滿足(cache size) / (associativity) ≤ page size。那麼問題來了,如果一個緩存大小為64KB,採用2路相聯,頁大小>=4k,那麼可以進行并行訪問TLB & Cache嗎?很顯然不能,如下

緩存大小:64KB = 216     ————-》 C = 16

組相聯:2                        ————-》 A = 1

頁大小: 4KB = 212        ————–》P >= 12

那麼問題又來了,對於一個16位的虛擬地址,頁大小為64字節,緩存大小為256b,採用8路相聯的1級緩存且有16塊,那麼可以并行訪問TLB &Cache嗎?請輸出原因。

總結

本節我們詳細介紹了TLB &Cache二者的關係,採用并行訪問通過VPN查找TLB,VPO查詢緩存同時進行來提高訪問速度。下一節我們進入頁表數據結構的詳細講解,謝謝。 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

防疫封鎖 馬達加斯加狐猴族群獲得喘息

摘錄自2020年9月24日公視報導

安達西貝自然保護區是馬達加斯加島生態觀光的熱門地點之一,過去五個月因為新冠病毒疫情造成的封鎖以及邊境管制,當地最具代表性的動物狐猴,在原始雨林裡享受了沒有人類嘈雜群聚,寧靜自得的生活。島內九月起放寬了封鎖政策,觀光人數開始緩步回升,但因為國際航班仍然停擺,多數是馬達加斯加人自己的島內旅遊。

3月起陷入封鎖寒冬的旅遊業者,樂見顧客回歸,但富裕的外國觀光客進不來,仍然入不敷出。經濟壓力也傷害了自然環境。森林嚮導發現,最近林木被濫伐破壞的情況比過去30年都要嚴重。

馬達加斯加的旅遊業佔全國經濟的7%,堪稱重要支柱,而雨林生態體系脆弱,全國上百種的狐猴,幾乎都已經因為盜獵、暖化與森林砍伐,名列國際自然保護聯盟的紅色瀕危名單,其中30種更已經是極度瀕危,離滅絕只差一步。

生物多樣性
國際新聞
馬達加斯加
防疫
狐猴
動物與大環境變遷

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

福島輻射污染土再利用 實驗種出超標作物

文:宋瑞文(媽媽監督核電廠聯盟特約撰述)

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

福島農夫的七種土質實測:土壤輻射污染越高,作物污染越嚴重

文:宋瑞文(媽媽監督核電廠聯盟特約撰述)

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?