国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

[Asp.net5]Caching-緩存架構(gòu)與源碼分析

2019-11-14 14:20:10
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

首先奉獻(xiàn)caching的開(kāi)源地址[微軟源碼]

1.工程架構(gòu)

 

為了提高程序效率,我們經(jīng)常將一些不頻繁修改,但是使用了還很大的數(shù)據(jù)進(jìn)行緩存。尤其是互聯(lián)網(wǎng)產(chǎn)品,緩存可以說(shuō)是提升效率優(yōu)化第一利器。微軟為我們實(shí)現(xiàn)了倆種緩存方式:內(nèi)存緩存、分布式緩存。個(gè)人理解如果緩存在前端電腦內(nèi)存的緩存叫做內(nèi)存緩存,如果緩存在其它設(shè)備上,那么叫做分布式緩存。

  • 倆種緩存方式的優(yōu)缺點(diǎn)

  我開(kāi)發(fā)程序經(jīng)歷過(guò)三個(gè)時(shí)間點(diǎn),開(kāi)始的時(shí)候從來(lái)不使用緩存,之后將數(shù)據(jù)緩存在內(nèi)存中,最后使用分布式緩存。內(nèi)存緩存的優(yōu)點(diǎn)是速度快,缺點(diǎn)是內(nèi)存損耗比較大,可能緩存的數(shù)據(jù)太大的時(shí)候就放不下了,另外一個(gè)缺點(diǎn)就是對(duì)于多前端程序的原則上是不支持的。而分布式緩存的優(yōu)點(diǎn)是,理論上緩存大小沒(méi)有上線,可以通過(guò)擴(kuò)充物理硬件進(jìn)行擴(kuò)展,對(duì)于多前端支持的較好。

Microsoft.Framework.Caching.Abstractions

這個(gè)工程定義的是緩存的整體架構(gòu)。我們的思想是面向接口編程,而不是面向?qū)崿F(xiàn)編程。所以該工程定義了我們想要的接口

從上圖顯而易見(jiàn),微軟將內(nèi)存緩存和分布式緩存割裂開(kāi)來(lái),而不是我們一般意義上定義一個(gè)ICache接口,之后讓IMemoryCache和IDistributedCache分別繼承ICache接口。

所以我們用分布式緩存,內(nèi)存緩存原則不能無(wú)縫的直接切換。需要我們修改程序代碼,或者進(jìn)行適配封裝。

  • 分布式緩存

   這部分包含內(nèi)容只包含簡(jiǎn)單的倆點(diǎn):配置項(xiàng)(DistributedCacheEntryOptions)、緩存接口(IDistributedCache)。而DistributedCacheEntryExtentions是DistributedCacheEntryOptions的擴(kuò)展方法包裝類(lèi),CaceheExtensions是IDistributedCache擴(kuò)展方法包裝類(lèi),CacheItemPRiority是優(yōu)先級(jí)枚舉。

  • 內(nèi)存緩存

  內(nèi)存緩存,微軟的設(shè)計(jì)就比較復(fù)雜,考慮到方方面面。首先時(shí)緩存的配置項(xiàng)(IMemoryCacheEntryOptions)、緩存接口(IMemoryCache)以及它們擴(kuò)展項(xiàng)(MemoryCacheEntryExtentions、CacheExtentions)。

  但是微軟的想法,緩存不止應(yīng)該只有過(guò)期失效,當(dāng)我程序update一個(gè)字段后,我想通知內(nèi)存緩存,我更改了,那又該怎么辦呢?于是微軟設(shè)計(jì)了右上角的部分(*由于代碼的持續(xù)更新原因右上角部分的接口已經(jīng)被去掉,由IList<IChangeToken> ExpirationTokens { get; }屬性替代,但是原則都是一樣的,即外部通知內(nèi)部,數(shù)據(jù)已經(jīng)更新)。

  既然外部數(shù)據(jù)更新能通知緩存,那反向呢?緩存更新是否能夠通知外部使用對(duì)象呢?答案是這個(gè)可以支持,所有上邊框,下面的部分。

  既然能外部修改通知內(nèi)部,內(nèi)部修改也能通知外部應(yīng)用程序。設(shè)計(jì)已經(jīng)趨近完美了?微軟說(shuō)還不夠,于是上圖左邊的部分產(chǎn)生了。它的意義就是,我可以為緩存創(chuàng)建一個(gè)范圍,至于范圍是做什么的?答案是“我也不知道”,但是從內(nèi)存緩存的實(shí)現(xiàn)上來(lái)看,是用于整體緩存token等信息的。

  緩存配置項(xiàng)的時(shí)間選項(xiàng):AbsoluteExpiration、AbsoluteExpirationRelativeToNow、SlidingExpiration。分別表示的是絕對(duì)的過(guò)期時(shí)間點(diǎn)、相對(duì)于現(xiàn)在多久的絕對(duì)過(guò)期時(shí)間點(diǎn),有效期時(shí)長(zhǎng)。我們注意下類(lèi)型AbsoluteExpiration是DateTimeOffset不是DateTime。(*DateTimeOffset 是對(duì)于1970年1月1日0時(shí)的時(shí)間偏移量,和DateTime相比,缺少時(shí)區(qū)的概念。而此處不需要有時(shí)區(qū)相關(guān)概念,所以選用了DateTimeOffset )。

 

 Microsoft.Extensions.Caching.Memory

  內(nèi)存緩存的實(shí)現(xiàn)。此處代碼結(jié)構(gòu)如下圖所示:

  • 大邏輯

  1,緩存太大時(shí),壓縮緩存空間(個(gè)人理解)

  系統(tǒng)創(chuàng)建內(nèi)存緩存對(duì)象(MemoryCache)的時(shí)候,同時(shí)創(chuàng)建GcNotification對(duì)象,之后GcNotification對(duì)象立馬失效。GC需要析構(gòu)的時(shí)候,會(huì)調(diào)用GcNotification的析構(gòu)函數(shù),析構(gòu)函數(shù)被調(diào)用后會(huì)執(zhí)行CallBack函數(shù)(定義在MemoryCache),之后再次注冊(cè)析構(gòu)函數(shù),循環(huán)往復(fù)的如此。所以當(dāng)內(nèi)存占用太高的時(shí)候,緩存會(huì)縮減緩存空間。

        if (reRegister && !Environment.HasShutdownStarted)            {                GC.ReRegisterForFinalize(this);            }    
注冊(cè)析構(gòu)函數(shù)

  2,緩存對(duì)象(MemoryCache)的釋放,沒(méi)有對(duì)象引用緩存的話,難免GC會(huì)回收緩存對(duì)象。那么怎么避免緩存被GC回收?下面代碼的思路還是不錯(cuò)的

        ~MemoryCache()        {            Dispose(false);        }        public void Dispose()        {            Dispose(true);        }        protected virtual void Dispose(bool disposing)        {            if (!_disposed)            {                if (disposing)                {                    GC.SuppressFinalize(this);                }                _disposed = true;            }        }        private void CheckDisposed()        {            if (_disposed)            {                throw new ObjectDisposedException(typeof(MemoryCache).FullName);            }        }
緩存對(duì)象析構(gòu)

  3,IEntryLink對(duì)象的跨線程訪問(wèn)

  緩存過(guò)期的時(shí)候,很可能不是本線程訪問(wèn)的,可能是另外一個(gè)線程,通過(guò)獲取IEntryLink,之后通過(guò)IChangeToken對(duì)象通知緩存,所以不同線程間必須是可以共享IEntryLink對(duì)象。此處使用的是CallContext.LogicalGetData與CallContext.LogicalSetData。關(guān)于線程見(jiàn)數(shù)據(jù)通信,請(qǐng)參考“如何實(shí)現(xiàn)對(duì)上下文(Context)數(shù)據(jù)的統(tǒng)一管理”

    internal static class EntryLinkHelpers    {        private const string ContextLinkDataName = "EntryLinkHelpers.ContextLink";        public static EntryLink ContextLink        {            get            {                var handle = CallContext.LogicalGetData(ContextLinkDataName) as ObjectHandle;                if (handle == null)                {                    return null;                }                return handle.Unwrap() as EntryLink;            }            set            {                CallContext.LogicalSetData(ContextLinkDataName, new ObjectHandle(value));            }        }        internal static IEntryLink CreateLinkingScope()        {            var parentLink = ContextLink;            var newLink = new EntryLink(parent: parentLink);            ContextLink = newLink;            return newLink;        }        internal static void DisposeLinkingScope()        {            var currentLink = ContextLink;            var priorLink = ((EntryLink)currentLink).Parent;            ContextLink = priorLink;        }    }
EntryLinkHelpers代碼示例

 

 

未完待續(xù)......


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 志丹县| 库车县| 清苑县| 张掖市| 三都| 昭平县| 酉阳| 和硕县| 巴林右旗| 临颍县| 闸北区| 萨嘎县| 翁牛特旗| 福海县| 茶陵县| 奉化市| 邛崃市| 福鼎市| 宁波市| 宝丰县| 龙川县| 资中县| 农安县| 德安县| 公主岭市| 赤城县| 澄江县| 于都县| 米泉市| 武宣县| 淮安市| 西昌市| 故城县| 上杭县| 万载县| 同德县| 读书| 浪卡子县| 阿克陶县| 尉犁县| 新余市|