• 使用ReaderWriterLock优化文件缓存


        公司使用的文件缓存经常出现大量的并发冲突,主要原因有两个:一个是读取文件时刚好文件被删除了,这样会抛出找不到文件的异常; 另一个是资源权限争抢的问题,可能会导致没有权限操作的情况。
        ReaderWriterLock类实现了多用户读/单用户写的同步访问机制,可以使用此类对文件的读写进行加锁操作,因为文件缓存一般是大量读少量写的情况,所以非常适合使用ReaderWriterLock。
        1、读缓存文件时使用AcquireReaderLock方法,并设置1000ms超时操作。
            private string readfile(string filename)
            
    {
                FileStream fs 
    = null;
                
    try
                
    {
                    rwLock.AcquireReaderLock(
    1000);//获取读锁
                    fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                    
    byte[] buf = new byte[fs.Length];
                    fs.Read(buf, 
    0, (int)fs.Length);
                    
    string xml = Encoding.UTF8.GetString(buf);
                    
    return xml;
                }

                
    catch (FileNotFoundException)//2008-01-24 add
                {
                    
    return null;
                }

                
    finally
                
    {
                    
    if (fs != null)
                    
    {
                        fs.Close();
                        fs.Dispose();
                        fs 
    = null;
                    }

                    rwLock.ReleaseReaderLock();
    //释放读锁
                }

            }

    2、添加缓存文件时使用AcquireWriterLock方法获取写锁。
            public void Add(string key, object value)
            
    {
                
    if (key == nullreturn;
                
    if (value == null)
                
    {
                    Remove(key);
                    
    return;
                }

                
    string fn = makefilename(makekey(key));
                
    string dir = Path.GetDirectoryName(fn);
                
    if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
                
    string xml = makevalue(value);
                
    //File.WriteAllText(fn, xml, Encoding.UTF8);

                FileStream fs 
    = null;
                
    try
                
    {
                    rwLock.AcquireWriterLock(
    1000);//获取写锁
                    fs = new FileStream(fn, FileMode.Create, FileAccess.Write, FileShare.Read);
                    
    byte[] buf = Encoding.UTF8.GetBytes(xml);
                    fs.Write(buf, 
    0, buf.Length);
                }

                
    finally
                
    {
                    
    if (fs != null)
                    
    {
                        fs.Close();
                        fs.Dispose();
                        fs 
    = null;
                    }

                    rwLock.ReleaseWriterLock();
    //释放写锁
                }


            }

    3、在删除缓存文件时也通过AcquireWriterLock获取写锁。
            public void Remove(string key)
            
    {
                
    if (key == nullreturn;
                
    string fileName = makefilename(makekey(key));

                
    try
                
    {
                    rwLock.AcquireWriterLock(
    1000);//获取写锁
                    File.Delete(fileName);
                }

                
    finally
                
    {
                    rwLock.ReleaseWriterLock();
    //释放写锁
                }



            }

    另外还写了一个测试程序对优化了的文件缓存进行并发访问测试。
    //#define usetry
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Threading;
    using System.Diagnostics;
    namespace CJB.Caching.FileSystem.Test
    {
        
    class Program
        
    {
            
    static long ElapsedTime = 0;
            
    static readonly object ElapsedTimeLock = new object();
            
    static long Counter = 0;

            
    static void Main(string[] args)
            
    {
                Thread t1 
    = new Thread(ReadTest);
                Thread t2 
    = new Thread(ReadTest);
                Thread t3 
    = new Thread(ReadTest);
                Thread t4 
    = new Thread(WriteTest);
                Thread t5 
    = new Thread(WriteTest);
                t1.Start(); 
    //t1.Join();
                t2.Start(); //t2.Join();
                t3.Start(); //t3.Join();
                t4.Start(); //t4.Join();
                t5.Start(); //t5.Join();


                Console.ReadLine();
                Console.WriteLine(String.Format(
    "程序完成调用{0}次数", Counter));
                Console.WriteLine(String.Format(
    "程序运行时间{0}毫秒", ElapsedTime));
                
    while (Console.ReadLine() != "q")
                
    {
                    Console.WriteLine(
    "请输入q退出程序");
                }

            }


            
    static void ReadTest()
            
    {
                TCache
    <string> tCache = new TCache<string>(TCacheType.FSCacheTest);
                
    string cacheKey = tCache.GetCacheKey("billok");

                Stopwatch sw 
    = null;
                
    for (int i = 0; i < 1000; i++)
                
    {
                    sw 
    = Stopwatch.StartNew();
    #if(usetry)
                    
    try
                    
    {
    #endif
                        
    string result = tCache.GetValue(cacheKey, delegate() return "ReadTest" + i.ToString(); });
                        Console.WriteLine(result);
    #if(usetry)
                    }

                    
    catch { }
    #endif
                    
    long ms = sw.ElapsedMilliseconds;
                    
    lock (ElapsedTimeLock)
                    
    {
                        ElapsedTime 
    += ms;
                    }

                    Interlocked.Increment(
    ref Counter);
                    Thread.Sleep(
    10);
                }

            }


            
    static void WriteTest()
            
    {
                TCache
    <string> tCache = new TCache<string>(TCacheType.FSCacheTest);
                
    string cacheKey = tCache.GetCacheKey("billok");

                Stopwatch sw 
    = null;
                
    for (int i = 0; i < 1000; i++)
                
    {
                    sw 
    = Stopwatch.StartNew();
    #if(usetry)
                    
    try
                    
    {
    #endif
                        tCache.Remove(cacheKey);
                        Console.WriteLine(
    "删除" + cacheKey);
    #if(usetry)
                    }

                    
    catch { }
    #endif
                    
    long ms = sw.ElapsedMilliseconds;
                    
    lock (ElapsedTimeLock)
                    
    {
                        ElapsedTime 
    += ms;
                    }

                    Interlocked.Increment(
    ref Counter);
                    Thread.Sleep(
    10);
                }

            }

        }

    }

    测试使用了Interlocked类来同步记录总共的读写次数,使用lock来同步记录总共耗时。
    注意使用Thread.Sleep(10);可以保证测试程序的并发量,防止在一个非常小的一个时间片中就耗掉大量的测试操作。
  • 相关阅读:
    大约PCA算法学习总结
    内部硬盘的硬件结构和工作原理进行了详细解释
    DWZ使用注意事项
    cocos2d-x 在XML分析和数据存储
    HTML精确定位:scrollLeft,scrollWidth,clientWidth,offsetWidth完全详细的说明
    hdu 1114 Piggy-Bank
    getResources()方法
    人机博弈-吃跳棋游戏(三)代移动
    Oracle 11g client安装和配置。
    的微信公众号开发 图灵机器人接口允许调用自己的微通道成为一个智能机器人
  • 原文地址:https://www.cnblogs.com/chenjunbiao/p/1760222.html
Copyright © 2020-2023  润新知