Winform裏面的緩存,MemoryCache使用

緩存在不少狀況下須要用到,合理利用緩存能夠一方面能夠提升程序的響應速度,同時能夠減小對特定資源訪問的壓力。本文主要針對本身在Winform方面的緩存使用作一個引導性的介紹,但願你們可以從中瞭解一些緩存的使用場景和使用方法。緩存是一箇中大型系統所必須考慮的問題。爲了不每次請求都去訪問後臺的資源(例如數據庫),咱們通常會考慮將一些更新不是很頻繁的,能夠重用的數據,經過必定的方式臨時地保存起來,後續的請求根據狀況能夠直接訪問這些保存起來的數據。這種機制就是所謂的緩存機制。html

.NET 4.0的緩存功能主要由三部分組成:System.Runtime.Caching,System.Web.Caching.Cache和Output Cache。web

MemoryCache對象:這是在.NET 4.0中新增的緩存框架,在Namespace:System.Runtime.Caching ,Assembly:System.Runtime.Caching.dll中數據庫

System.Web.Caching.Cache這個則是在.NET2.0開始就一直存在的緩存對象,通常主要用在Web中,固然也能夠用於Winform裏面,不過要引用System.Web.dll。緩存

Output Cache則是Asp.NET裏面使用的,在ASP.NET 4.0以前的版本都是直接使用System.Web.Caching.Cache來緩存HTML片斷。在ASP.NET 4.0中對它進行了從新設計,提供了一個OutputCacheProvider供開發人員進行擴展,可是它默認狀況下,仍然使用System.Web.Caching.Cache來作作緩存。框架

一、自定義Hastable的緩存處理。

除了上面三種的緩存機制,通常咱們還能夠在靜態對象裏面經過HashTable或者Dictionary的方式進行自定義的緩存存儲和使用。ide

例如我在我本身所開發的程序裏面,都使用了工廠類來建立業務對象,因爲建立業務對象以及數據訪問層對象,是一個在界面或者中間層反覆調用的操做,所以須要把常常調用的對象把它存儲起來,下載調用的時候,直接從內存中取出來便可。以下面的BLLFactory類,就是一個基於泛型對象的業務類的建立操做,使用了基於Hashtable的靜態對象進行緩存處理。函數

複製代碼
    /// <summary>
    /// 對業務類進行構造的工廠類
    /// </summary>
    /// <typeparam name="T">業務對象類型</typeparam>
    public class BLLFactory<T> where T : class
    {
        private static Hashtable objCache = new Hashtable();
        private static object syncRoot = new Object();

        /// <summary>
        /// 建立或者從緩存中獲取對應業務類的實例
        /// </summary>
        public static T Instance
        {
            get
            {
                string CacheKey = typeof(T).FullName;
                T bll = (T)objCache[CacheKey];  //從緩存讀取  
                if (bll == null)
                {
                    lock (syncRoot)
                    {
                        if (bll == null)
                        {
                            bll = Reflect<T>.Create(typeof(T).FullName, typeof(T).Assembly.GetName().Name); //反射建立,並緩存
                            objCache.Add(typeof(T).FullName, bll);
                        }
                    }
                }
                return bll;
            }
        }
    } 
複製代碼

二、使用.NET4.0的MemoryCache對象實現緩存post

MemoryCache的使用網上介紹的很少,不過這個是.NET4.0新引入的緩存對象,估計主要是替換原來企業庫的緩存模塊,使得.NET的緩存能夠無處不在,而不用基於特定的Windows版本上使用。性能

首先咱們使用來建立一個基於MemoryCache的輔助類MemoryCacheHelper,方便調用進行緩存處理。測試

複製代碼
    /// <summary>
    /// 基於MemoryCache的緩存輔助類
    /// </summary>
    public static class MemoryCacheHelper
    {
        private static readonly Object _locker = new object();
     
        public static T GetCacheItem<T>(String key, Func<T> cachePopulate, TimeSpan? slidingExpiration = null, DateTime? absoluteExpiration = null)
        {
            if(String.IsNullOrWhiteSpace(key)) throw new ArgumentException("Invalid cache key");
            if(cachePopulate == null) throw new ArgumentNullException("cachePopulate");
            if(slidingExpiration == null && absoluteExpiration == null) throw new ArgumentException("Either a sliding expiration or absolute must be provided");
     
            if(MemoryCache.Default[key] == null)
            {
                lock(_locker)
                {
                    if(MemoryCache.Default[key] == null)
                    {
                        var item = new CacheItem(key, cachePopulate());
                        var policy = CreatePolicy(slidingExpiration, absoluteExpiration);
     
                        MemoryCache.Default.Add(item, policy);
                    }
                }
            }
     
            return (T)MemoryCache.Default[key];
        }
     
        private static CacheItemPolicy CreatePolicy(TimeSpan? slidingExpiration, DateTime? absoluteExpiration)
        {
            var policy = new CacheItemPolicy();
     
            if(absoluteExpiration.HasValue)
            {
                policy.AbsoluteExpiration = absoluteExpiration.Value;
            }
            else if(slidingExpiration.HasValue)
            {
                policy.SlidingExpiration = slidingExpiration.Value;
            }
     
            policy.Priority = CacheItemPriority.Default;
     
            return policy;
        }
    }
複製代碼

下面在給個通過改良的版本,供參考吧!

    /// <summary>
    /// 基於System.Runtime.Caching.dll中的MemoryCache的緩存輔助類
    /// </summary>
    public static class MemoryCacheHelper
    {
        
        private static readonly Object _locker = new object();

        /// <summary>
        /// 若是緩存中存在指定的key,則優先從緩存中返回
        /// </summary>
        /// <typeparam name="T">返回值類型</typeparam>
        /// <param name="key">緩存關鍵字</param>
        /// <param name="cachePopulate">須要執行的方法、Lambda表達式、(匿名)代理等。
        /// <code>例如:() => "測試",  或者 
        /// delegate () { return new aaa("測試"); },
        /// </code>
        /// </param>
        /// <param name="slidingExpiration">滑動窗口模式的使用過時時間</param>
        /// <param name="absoluteExpiration">絕對過時時間</param>
        /// <returns></returns>
        public static T GetCacheItem<T>(String key, Func<T> cachePopulate, TimeSpan? slidingExpiration = null, DateTime? absoluteExpiration = null)
        {
            if (String.IsNullOrWhiteSpace(key)) throw new ArgumentException("Invalid cache key");
            if (cachePopulate == null) throw new ArgumentNullException("cachePopulate");
            if (slidingExpiration == null && absoluteExpiration == null) throw new ArgumentException("Either a sliding expiration or absolute must be provided");

            if (MemoryCache.Default[key] == null)
            {
                lock (_locker)
                {
                    if (MemoryCache.Default[key] == null)
                    {
                        var item = new CacheItem(key, cachePopulate());
                        var policy = CreatePolicy(slidingExpiration, absoluteExpiration);

                        MemoryCache.Default.Add(item, policy);
                    }
                }
            }

            return (T)((MemoryCache.Default[key] is T) ? MemoryCache.Default[key] : default(T));
            //return (T)MemoryCache.Default[key];
        }


        /// <summary>
        /// 若是緩存中存在指定的key,則優先從緩存中返回
        /// </summary>
        /// <typeparam name="T">返回值類型</typeparam>
        /// <param name="key">緩存關鍵字</param>
        /// <param name="cachePopulate">須要執行的方法、Lambda表達式、(匿名)代理等。
        /// <code>例如:() => "測試",  或者 
        /// delegate () { return new aaa("測試"); },
        /// </code>
        /// </param>
        /// <param name="expirationTime">緩存過時時間</param>
        /// <param name="expirationTimeType">緩存過時時間類型</param>
        /// <param name="enabledCache">是否啓用緩存,若是false則每次都是直接執行被調方法cachePopulate,默認啓用,</param>
        /// <returns></returns>
        public static T GetCacheItem<T>(String key, Func<T> cachePopulate, TimeSpan expirationTime, ExpirationTimeType expirationTimeType, bool enabledCache = true)
        {
            if (String.IsNullOrWhiteSpace(key)) throw new ArgumentException("Invalid cache key");
            if (cachePopulate == null) throw new ArgumentNullException("cachePopulate");
            if (expirationTime == null) throw new ArgumentException("Either a sliding expiration must be provided");

            T tmp = default(T);

            if (enabledCache)
            {
                if (MemoryCache.Default[key] == null)
                {
                    lock (_locker)
                    {
                        if (MemoryCache.Default[key] == null)
                        {
                            Console.WriteLine("MemoryCache is null.");
                            CacheItem item = new CacheItem(key, cachePopulate());

                            CacheItemPolicy policy = null;
                            if (expirationTimeType == ExpirationTimeType.AbsoluteExpirationTimeType)
                                policy = CreatePolicy(null, DateTime.Now.Add(expirationTime));
                            else if (expirationTimeType == ExpirationTimeType.SlidingExpirationTimeType)
                                policy = CreatePolicy(expirationTime, null);
                            else
                                policy = CreatePolicy(TimeSpan.Zero, null);

                            MemoryCache.Default.Add(item, policy);
                        }
                    }
                }
                tmp = (MemoryCache.Default[key] is T) ? (T)MemoryCache.Default[key] : default(T);
                //return (MemoryCache.Default[key] is T) ? (T)MemoryCache.Default[key] : default(T);
                //return (T)MemoryCache.Default[key];
            }
            else
            {
                tmp = cachePopulate();
            }

            return tmp;
        }

        
        /// <summary>
        /// 從緩存中移除知道鍵值的緩存對象
        /// </summary>
        /// <param name="key">緩存對象的鍵</param>
        /// <returns></returns>
        public static bool RemoveCacheItem(string key)
        {
            bool isRemove = false;
            try
            {
                if (MemoryCache.Default[key] != null)
                {
                    lock (_locker)
                    {
                        if (MemoryCache.Default[key] != null)
                        {
                            MemoryCache.Default.Remove(key);
                        }
                    }
                }
                isRemove = true;
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return isRemove;
        }

        
        /// <summary>
        /// 構造緩存過時時間和優先級
        /// </summary>
        /// <param name="slidingExpiration">滑動窗口模式的使用過時時間</param>
        /// <param name="absoluteExpiration">絕對過時時間</param>
        /// <returns></returns>
        private static CacheItemPolicy CreatePolicy(TimeSpan? slidingExpiration, DateTime? absoluteExpiration)
        {
            if (slidingExpiration == null && absoluteExpiration == null)
                throw new ArgumentException("Either a sliding expiration or absolute must be provided");

            CacheItemPolicy policy = new CacheItemPolicy();

            if (slidingExpiration.HasValue)
            {
                policy.SlidingExpiration = slidingExpiration.Value;
            }
            else if (absoluteExpiration.HasValue)
            {
                policy.AbsoluteExpiration = absoluteExpiration.Value;
            }
            policy.Priority = CacheItemPriority.Default;

            //List<string> filePaths = new List<string>();
            //filePaths.Add("c:\\cache\\example.txt");
            //policy.ChangeMonitors.Add(new HostFileChangeMonitor(filePaths));

            return policy;
        }

        
        /// <summary>
        /// 緩存過時時間類型
        /// </summary>
        public enum ExpirationTimeType
        {
            /// <summary>
            /// 滑動窗口模式的使用過時時間
            /// </summary>
            SlidingExpirationTimeType = 1,

            /// <summary>
            /// 絕對過時時間
            /// </summary>
            AbsoluteExpirationTimeType = 2
        }


    }
View Code

 

這個輔助類只有一個public方法,就是GetCacheItem,使用的時候,須要指定key和獲取數據的處理代理,還有緩存的過時時間,是基於TimeSpan的仍是基於絕對時間的,選擇其一。

上面的輔助類,咱們在什麼狀況下會使用到呢?

假如在一個工做流模塊中用到了人員ID,而人員ID須要進行人員名稱的轉義,人員信息咱們通常知道放在權限系統模塊裏面,那麼若是在工做流裏面須要頻繁對人員ID進行轉義,那麼就須要方法調用權限系統的接口模塊,這樣處理就可使用緩存模塊進行優化處理的了。

複製代碼
        void gridView1_CustomColumnDisplayText(object sender, DevExpress.XtraGrid.Views.Base.CustomColumnDisplayTextEventArgs e)
        {
            if (e.Column.FieldName.Equals("ProcUser") || e.Column.FieldName.Equals("ProcUid") || e.Column.FieldName.Equals("UserId"))
            {
                if (e.Value != null)
                {
                    e.DisplayText = SecurityHelper.GetUserFullName(e.Value.ToString());
                }
            }
        }
複製代碼

其中的SecurityHelper.GetUserFullName是我對調用進行基於緩存的二次封裝,具體邏輯以下所示。

複製代碼
        /// <summary>
        /// 根據用戶的ID,獲取用戶的全名,並放到緩存裏面
        /// </summary>
        /// <param name="userId">用戶的ID</param>
        /// <returns></returns>
        public static string GetUserFullName(string userId)
        {            
            string key = "Security_UserFullName" + userId;
            string fullName = MemoryCacheHelper.GetCacheItem<string>(key,
                delegate() { return BLLFactory<User>.Instance.GetFullNameByID(userId.ToInt32()); },
                new TimeSpan(0, 30, 0));//30分鐘過時
            return fullName;
        }
複製代碼

MemoryCacheHelper的方法GetCacheItem裏面的Func<T>我使用了一個匿名函數用來獲取緩存的值。

delegate() { return BLLFactory<User>.Instance.GetFullNameByID(userId.ToInt32()); }

而調用BLLFactory<User>.Instance.GetFullNameByID則是從數據庫裏面獲取對應的數據了。

這樣在第一次或者緩存過時的時候,自動調用業務對象類的方法來獲取數據了。

最後,在界面上調用GetUserFullName的方法便可實現基於緩存方式的調用,程序第一次使用的,碰到指定的鍵沒有數據,就去數據庫裏面獲取,之後碰到該鍵,則直接獲取緩存的數據了。

下面圖形是程序具體的實現效果。

固然,以上兩種方式都還能夠經過AOP的注入方式實現代碼的簡化操做,不過因爲對AOP的引入,會涉及到更多的知識點,並且熟悉程序還不夠,因此依然採用較爲經常使用的方式來處理緩存的數據。

 

 

出處:https://www.cnblogs.com/wuhuacong/p/3526335.html

======================================================================================

摘要

在對winform作的項目優化的時候,首先想到的是對查詢,並不常常變化的數據進行緩存,但對web項目來講有System.Web.Caching.Cache類進行緩存,那麼winform端該如何呢?你可能會想到,存到文件中,但那可能有問題,文件操做權限問題,IO操做性能問題。

解決辦法

針對exe的項目,可使用MemoryCache這個類,進行內存級別的緩存。

輔助類

複製代碼
    /// <summary>
    /// 基於MemoryCache的緩存輔助類
    /// </summary>
    public static class MemoryCacheHelper
    {
        private static readonly Object _locker = new object();

        public static T FindCacheItem<T>(string key, Func<T> cachePopulate, TimeSpan? slidingExpiration = null,
DateTime? absoluteExpiration = null) { if (String.IsNullOrWhiteSpace(key)) { throw new ArgumentException("Invalid cache key"); } if (cachePopulate == null) { throw new ArgumentNullException("cachePopulate"); } if (slidingExpiration == null && absoluteExpiration == null) { throw new ArgumentException("Either a sliding expiration or absolute must be provided"); } if (MemoryCache.Default[key] == null) { lock (_locker) { if (MemoryCache.Default[key] == null) { var item = new CacheItem(key, cachePopulate()); var policy = CreatePolicy(slidingExpiration, absoluteExpiration); MemoryCache.Default.Add(item, policy); } } } return (T)MemoryCache.Default[key]; } /// <summary> /// 移除緩存 /// </summary> /// <param name="key"></param> public static void RemoveCache(string key) { MemoryCache.Default.Remove(key); } private static CacheItemPolicy CreatePolicy(TimeSpan? slidingExpiration, DateTime? absoluteExpiration) { var policy = new CacheItemPolicy(); if (absoluteExpiration.HasValue) { policy.AbsoluteExpiration = absoluteExpiration.Value; } else if (slidingExpiration.HasValue) { policy.SlidingExpiration = slidingExpiration.Value; } policy.Priority = CacheItemPriority.Default; return policy; } }
複製代碼

測試

複製代碼
  class Program
    {
        static void Main(string[] args)
        {
            string cacheKey = "person_key";
            Person p = MemoryCacheHelper.FindCacheItem<Person>(cacheKey,
                () =>
                {
                    return new Person() { Id = Guid.NewGuid(), Name = "wolfy" };
                }, new TimeSpan(0, 30, 0));
            if (p != null)
            {
                Console.WriteLine(p.ToString());
            }
            Console.WriteLine("獲取緩存中數據");
            Person p2 = MemoryCacheHelper.FindCacheItem<Person>(cacheKey,
                () =>
                {
                    return new Person() { Id = Guid.NewGuid(), Name = "wolfy" };
                }, new TimeSpan(0, 30, 0));
            if (p2 != null)
            {
                Console.WriteLine(p2.ToString());
            }
            MemoryCacheHelper.RemoveCache(cacheKey);
            Person p3 = MemoryCacheHelper.FindCacheItem<Person>(cacheKey,
               () =>
               {
                   return new Person() { Id = Guid.NewGuid(), Name = "wolfy" };
               }, new TimeSpan(0, 30, 0));
            if (p3 != null)
            {
                Console.WriteLine(p3.ToString());
            }
            Console.Read();
        }

    }
    public class Person
    {
        public Guid Id { set; get; }
        public string Name { set; get; }
        public override string ToString()
        {
            return Id.ToString() + "\t" + Name;
        }
    }
複製代碼

 

參考:

https://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache(v=vs.110).aspx

 

出處:https://www.cnblogs.com/wolf-sun/p/7251343.html

相關文章
相關標籤/搜索