2

我们有一个大量使用的 .Net 3.5 应用程序,它读取“创建成本高”的数据并将其缓存。应用程序基于它而不是“被另一个进程使用”来读取\写入文件。如果其他进程正在读取和写入文件,则应用程序进入睡眠状态(一段时间)并重试。这是读写文件的正确方法吗?请指教。

public void Add<T>(string key, CacheItem<T> item)
        {
            bool fileInUse = false;
            while (!fileInUse)
            {
                try
                {
                    using (Stream stream = new FileStream(Path.Combine(cachePath, key+".bin"), FileMode.Create, FileAccess.Write, FileShare.None))
                    {
                        Serializer.NonGeneric.Serialize(stream, item);
                    }
                    fileInUse = true;
                }
                catch (IOException ex)
                {
                    if (ex.Message.Contains("being used by another process"))
                    {
                        //Poll till the file is free to be used by this process
                        Thread.Sleep(100);
                        fileInUse = false;
                    }
                }
            }            
        }        

public CacheItem<T> Get<T>(string key, Type type)
        {
            CacheItem<T> item = null;

            FileInfo fileInfo = new FileInfo(Path.Combine(cachePath, key+".bin"));
            fileInfo.Refresh();
            if (fileInfo.Exists)
            {
                bool fileInUse = false;
                while (!fileInUse)
                {
                    try
                    {
                        using (Stream stream = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.None))
                        {
                            object objectTemp = Serializer.NonGeneric.Deserialize(type, stream);
                            item = (CacheItem<T>)objectTemp;
                        }
                        fileInUse = true;
                    }
                    catch(IOException ex) 
                    {
                        if (ex.Message.Contains("being used by another process"))
                        {
                            //Poll till the file is free to be used by this process
                            Thread.Sleep(100);
                            fileInUse = false;
                        }
                    }
                }               
            }                       
            return item;                                   
        }
4

2 回答 2

2

您可以在其上添加一个全局互斥锁,以避免等待超过绝对必要的时间。

全局互斥体是通过将非空值传递nameMutex Constructor来创建的。

好处:

  • Mutex 将允许您在文件可用后立即唤醒,而不是平均等待 50 毫秒。
  • 互斥锁让你睡一次一次,而不是反复睡觉/醒来。休眠的线程由操作系统非常有效地处理并且几乎不消耗任何资源。
  • 获得互斥锁后,打开文件几乎 100% 可能成功,而不是在成功之前可能多次失败。

总而言之,您不仅会更快,而且在此过程中可能会消耗更少的 CPU 周期

于 2012-04-13T19:25:44.713 回答
1

如果这是您经常做的事情(因此性能是一个问题),我会建议完全不同的设计。

您应该有一个公共静态方法(或单例中的方法),它接受一个字符串(如果这适用于多个文件,还有一个文件名)。在该方法中,它应该将该字符串放入BlockingCollection<string>. Dictionary<string, BlockingCollection<string>>(通过将文件名映射到该文件的队列,您可以只有一个,或每个文件一个。)

在大多数情况下(即缓冲区未满),想要将某些内容写入文件的任务只需将其添加到队列中,然后立即恢复工作。

然后,您需要有一个单独的线程/任务,它只是坐在那里从阻塞集合中读取(您应该只需要一个,即使您有很多阻塞集合)并将数据写入文件。由于只有一个线程写入文件,因此不需要围绕文件 IO 进行锁定,并且BlockingCollection旨在在此生产者/消费者模型中工作,并为您处理所有需要的锁定。

我建议BlockingColleciton对所有文件只使用一个,除非您找到一个令人信服的性能理由来尝试处理多个队列。管理起来会容易一些。

于 2012-04-13T19:33:28.997 回答