一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - ASP.NET教程 - ASP.NET Core - 緩存之內存緩存(下)

ASP.NET Core - 緩存之內存緩存(下)

2023-05-08 00:02未知服務器之家 ASP.NET教程

話接上篇 [ASP.NET Core - 緩存之內存緩存(上)],所以這里的目錄從 2.4 開始。 2.4 MemoryCacheEntryOptions MemoryCacheEntryOptions 是內存緩存配置類,可以通過它配置緩存相關的策略。除了上面講到的過期時間,我們還能夠設置下面這些: 設置緩

話接上篇 [ASP.NET Core - 緩存之內存緩存(上)],所以這里的目錄從 2.4 開始。

2.4 MemoryCacheEntryOptions

MemoryCacheEntryOptions 是內存緩存配置類,可以通過它配置緩存相關的策略。除了上面講到的過期時間,我們還能夠設置下面這些:

  • 設置緩存優先級。
  • 設置在從緩存中逐出條目后調用的 PostEvictionDelegate。
    回調在與從緩存中刪除項的代碼不同的線程上運行。
  • 限制緩存大小
var memoryCacheEntryOption = new MemoryCacheEntryOptions();
memoryCacheEntryOption.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(3);
// 緩存優先級,Low, Normal, High, NeverRemove,Normal是默認值,與緩存刪除時的策略有關
memoryCacheEntryOption.SetPriority(CacheItemPriority.Normal);
// 注冊緩存項刪除回調事件
memoryCacheEntryOption.RegisterPostEvictionCallback(PostEvictionDelegate);
_cache.Set(CacheKey, cacheValue, memoryCacheEntryOption);

public void PostEvictionDelegate(object cacheKey, object cacheValue, EvictionReason evictionReason, object state)
{
	var memoryCache = (IMemoryCache)state;

	Console.WriteLine($"Entry {cacheKey}:{cacheValue} was evicted: {evictionReason}.");
}

ASP.NET Core - 緩存之內存緩存(下)

緩存大小限制要配合 MemoryCache 實例的配置來使用。MemoryCache 實例可以選擇指定并強制實施大小限制。 緩存大小限制沒有定義的度量單位,因為緩存沒有度量條目大小的機制。 如果設置了緩存大小限制,則所有條目都必須指定大小。 ASP.NET Core 運行時不會根據內存壓力限制緩存大小。 由開發人員限制緩存大小。 指定的大小采用開發人員選擇的單位。

例如:

  • 如果 Web 應用主要緩存字符串,則每個緩存條目的大小可以是字符串長度。
  • 應用可以將所有條目的大小指定為 1,大小限制是條目計數。
    如果未設置 SizeLimit,則緩存會無限增長。 系統內存不足時,ASP.NET Core 運行時不會剪裁緩存。 應用必須構建為:
    • 限制緩存增長。
    • 在可用內存受限時調用 Compact 或 Remove。

這里的意思是,緩存大小沒有單位,我們可以設置一個總的大小,然后為每個緩存條目設置一個大小。如果沒有設置大小的情況下,緩存可能會無限增長,直至用完服務器上的所有內存。

// 我們可以在進行內存緩存注冊的時候設置緩存大小限制
services.AddMemoryCache(options =>
{
	options.SizeLimit = 1024;
});

// 之后設定每個緩存項的大小,可根據開發人員的判斷設置,例如這里無論多大都設置為 1,則最多有 1024 個緩存項
memoryCacheEntryOption.SetSize(1);
_cache.Set(CacheKey, cacheValue, memoryCacheEntryOption);

2.5 緩存清理

緩存到期后不會在后臺自動清理。 沒有計時器可以主動掃描緩存中的到期項。 而緩存上的任何活動(Get、Set、Remove)都可觸發在后臺掃描到期項。 如果使用了CancellationTokenSource ,則其計時器 (CancelAfter) 也會刪除條目并觸發掃描到期項,這個是下面要講到的。

除了在對緩存進行操作時,會觸發對相應的緩存項進行過期檢查之外,我們還可以通過手動調用 Remove 方法和 Compact 方法對緩存進行清理。

_cache.Remove(cacheKey);
_cache.Compact(.25);

Compact 方法會嘗試按以下順序刪除指定百分比的緩存:

  • 所有到期項。
  • 按優先級排列的項。 首先刪除最低優先級的項。
  • 最近最少使用的對象。
  • 絕對到期時間最短的項。
  • 可調到期時間最短的項。

永遠不會刪除優先級為 NeverRemove 的固定項。 上面的代碼的作用就是刪除cacheKey對于的緩存項,并調用 Compact 以刪除 25% 的緩存條目。

2.6 緩存組

緩存項的過期策略除了上面講到的過期時間的設置之外,還可以通過 CancellationChangeToken 來控制,通過它可以同時控制多個緩存對象的過期策略,實現相關的緩存同時過期,構成一個組的概念。

以下為示例代碼:

首先先定義兩個方法,將緩存設置和緩存讀取分開:

public interface ICacheService
{
	public void PrintDateTimeNow();

	public void SetGroupDateTime();

	public void PrintGroupDateTime();
}

public class CacheService : ICacheService 
{
	public const string CacheKey = "CacheTime";
	public const string DependentCancellationTokenSourceCacheKey = "DependentCancellationTokenSource";
	public const string ParentCacheKey = "Parent";
	public const string ChildCacheKey = "Chlid";
	private readonly IMemoryCache _cache;
	public CacheService(IMemoryCache memoryCache)
	{
		_cache = memoryCache;
	}

	public void PrintDateTimeNow()
	{
		var time = DateTime.Now;
		if (!_cache.TryGetValue(CacheKey, out DateTime cacheValue))
		{
			cacheValue = time;
			// 設置絕對過期時間
			// 兩種實現的功能是一樣的,只是時間設置的方式不同而已
			// 傳入的是 AbsoluteExpirationRelativeToNow, 相對當前的絕對過期時間,傳入時間差,會根據當前時間算出絕對過期時間
			// _cache.Set(CacheKey, cacheValue, TimeSpan.FromSeconds(2));
			// 傳入的是 AbsoluteExpiration,絕對過期時間,傳入一個DateTimeOffset對象,需要明確的指定具體的時間
			// _cache.Set(CacheKey, cacheValue, DateTimeOffset.Now.AddSeconds(2));

			//var memoryCacheEntryOption = new MemoryCacheEntryOptions();
			//// 滑動過期時間是一個相對時間
			//memoryCacheEntryOption.SlidingExpiration = TimeSpan.FromSeconds(3);
			//_cache.Set(CacheKey, cacheValue, memoryCacheEntryOption);

			var memoryCacheEntryOption = new MemoryCacheEntryOptions();
			memoryCacheEntryOption.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(3);
			// 緩存優先級,Low, Normal, High, NeverRemove,Normal是默認值,與緩存刪除時的策略有關
			memoryCacheEntryOption.SetPriority(CacheItemPriority.Normal);
			memoryCacheEntryOption.RegisterPostEvictionCallback(PostEvictionDelegate);
			// 之后設定每個緩存項的大小,可根據開發人員的判斷設置,例如這里無論多大都設置為 1,則最多有 1024 個緩存項
			memoryCacheEntryOption.SetSize(1);
			_cache.Set(CacheKey, cacheValue, memoryCacheEntryOption);
		}
		time = cacheValue;

		Console.WriteLine("緩存時間:" + time.ToString("yyyy-MM-dd HH:mm:ss"));
		Console.WriteLine("當前時間:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
	}

	public void PostEvictionDelegate(object cacheKey, object cacheValue, EvictionReason evictionReason, object state)
	{
		var memoryCache = (IMemoryCache)state;

		Console.WriteLine($"Entry {cacheKey}:{cacheValue} was evicted: {evictionReason}.");
	}

	public void SetGroupDateTime()
	{
		// 這里為了將 CancellationTokenSource 保存起來,以便在外部可以獲取得到
		var cancellationTokenSource = new CancellationTokenSource();
		_cache.Set(
			DependentCancellationTokenSourceCacheKey,
			cancellationTokenSource);

		using var parentCacheEntry = _cache.CreateEntry(ParentCacheKey);

		parentCacheEntry.Value = DateTime.Now;

		Task.Delay(TimeSpan.FromSeconds(1)).Wait();

		_cache.Set(
			ChildCacheKey,
			DateTime.Now,
			new CancellationChangeToken(cancellationTokenSource.Token));
	}

	public void PrintGroupDateTime()
	{
	   if(_cache.TryGetValue(ParentCacheKey, out DateTime parentCacheDateTime))
		{
			Console.WriteLine("ParentDateTime:" + parentCacheDateTime.ToString("yyyy-MM-dd HH:mm:ss"));
		}
		else
		{
			Console.WriteLine("ParentDateTime is canceled");
		}

		if (_cache.TryGetValue(ChildCacheKey, out DateTime childCacheDateTime))
		{
			Console.WriteLine("ChildDateTime:" + childCacheDateTime.ToString("yyyy-MM-dd HH:mm:ss"));
		}
		else
		{
			Console.WriteLine("ChildDateTime is canceled");
		}
	}
}

之后改造一下入口文件中的測試代碼:

var service = host.Services.GetRequiredService<ICacheService>();
service.SetGroupDateTime();

service.PrintGroupDateTime();

service.PrintGroupDateTime();

var cache = host.Services.GetRequiredService<IMemoryCache>();
var cancellationTokenSource = cache.Get<CancellationTokenSource>(CacheService.DependentCancellationTokenSourceCacheKey);
cancellationTokenSource.Cancel();

service.PrintGroupDateTime();

從控制臺輸出可以看得到前兩次緩存獲取正常,當調用 CancellationTokenSource.Cancel() 方法取消請求之后,緩存過期了。

ASP.NET Core - 緩存之內存緩存(下)

如果使用 CancellationTokenSource,則允許將多個緩存條目作為一個組逐出。 使用上述代碼中的 using 模式,在 using 范圍內創建的緩存條目會繼承觸發器和到期設置。不過這種方式只有 using 范圍的緩存項和 using 范圍內使用 CancellationTokenSource 的緩存項可以構成一個組,如果范圍內還有其他的緩存項,是不算在一個組內的。

ASP.NET Core - 緩存之內存緩存(下)

如果要把多個緩存項全部納入一個組,還可以用以下的方式:

_cache.Set(ParentCacheKey,
	DateTime.Now,
	new CancellationChangeToken(cancellationTokenSource.Token));

_cache.Set(
	ChildCacheKey,
	DateTime.Now,
	new CancellationChangeToken(cancellationTokenSource.Token));

_cache.Set(
	ChildsCacheKey,
	DateTime.Now,
	new CancellationChangeToken(cancellationTokenSource.Token));

ASP.NET Core - 緩存之內存緩存(下)

2.7 一些注意事項

  • 使用回調重新填充緩存項時:

    ? 多個請求可以發現緩存的鍵值為空,因為回調沒有完成。
    ? 這可能會導致多個線程重新填充緩存項。

  • 當使用一個緩存條目創建另一個緩存條目時,子條目會復制父條目的到期令牌和基于時間的到期設置。 手動刪除或更新父條目時,子條目不會過期。

官方文檔上還有另外幾條,但是我這邊在上面有講過了,這里就不再重復了。



參考文章:
ASP.NET Core 中的內存中緩存



ASP.NET Core 系列:

目錄:ASP.NET Core 系列總結
上一篇:ASP.NET Core - 緩存之內存緩存(上)

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 狠狠干2016| gay男男白袜chinese | 国产91精品久久久久久 | 久久青青草原精品国产软件 | 午夜片无码区在线观看 | 精品久久久久中文字幕日本 | 男同激情视频 | 免费被靠视频动漫 | 欧美日韩精品乱国产 | ak福利午夜在线观看 | 欧美一区不卡二区不卡三区 | avtt天堂网 手机资源 | 俄罗斯freeⅹ性欧美 | 久久精品国产在热亚洲 | 久久99国产视频 | 国产精品一二区 | 国产精品伊人 | 香蕉国产精品偷在线播放 | 日韩成本大片35分钟免费播放 | 青青青在线视频播放 | 亚洲国产日韩欧美在线vip1区 | 800精品国产导航 | 四虎永久免费地址ww417 | 99精品免费在线观看 | www.四虎.com| 99久久99热久久精品免费看 | 青青草成人在线 | 亚洲国产综合网 | 国产特黄一级一片免费 | 午夜无码国产理论在线 | 清纯唯美 亚洲 | 动态图啪啪120秒免费看 | 香蕉eeww99国产在线观看 | 校园春色偷拍自拍 | 成年性香蕉漫画在线观看 | 成人看片免费无限观看视频 | 女同志freelesvoices | 王晶三级作品 | 99久久国产综合精品麻豆 | 99久久精品无码一区二区毛片 | 日韩激情视频在线观看 |