我们有一个使用频繁的.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;
}
答案 0 :(得分:2)
您可以在其上添加全局互斥锁,以避免等待超过绝对必要。
通过将非空name
传递给Mutex Constructor来创建全局互斥锁。
优点:
总而言之,您不仅仅是更快,您可能会在此过程中消耗更少的CPU周期。
答案 1 :(得分:1)
如果这是你做了很多事情(因此性能问题),我会建议完全不同的设计。
你应该有一个公共静态方法(或单例中的方法),它接受一个字符串(如果这适用于多个文件,则为文件名)。在该方法中,它应该将该字符串放入BlockingCollection<string>
。 (通过Dictionary<string, BlockingCollection<string>>
可以只有一个或一个文件将文件名映射到该文件的队列。)
在大多数情况下(即缓冲区未满),想要将某些内容写入文件的任务只是将其添加到队列中,然后立即恢复工作。
然后你需要有一个单独的线程/任务,只是在那里读取阻塞集合(你应该只需要一个,即使你有很多阻塞集合)并将数据写入文件。由于只有一个线程写入文件,因此没有需要围绕文件IO的锁定,而BlockingCollection
旨在在此生产者/消费者模型中工作,并为您处理所有需要的锁定。
我建议只为所有文件使用一个BlockingColleciton
,除非您找到一个令人信服的性能原因来尝试处理多个队列。管理起来会容易得多。