读取\写入文件的正确方法:使用频繁的应用程序

时间:2012-04-13 19:22:23

标签: c# asp.net .net protobuf-net

我们有一个使用频繁的.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;                                   
        }

2 个答案:

答案 0 :(得分:2)

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

通过将非空name传递给Mutex Constructor来创建全局互斥锁。

优点:

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

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

答案 1 :(得分:1)

如果这是你做了很多事情(因此性能问题),我会建议完全不同的设计。

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

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

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

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