2012-04-13 56 views
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;         
     } 

回答

2

你可以在它的上面添加一個全球互斥體,以避免等待的時間超過絕對必要的。

全局互斥是通過將非空的name傳遞給Mutex Constructor來創建的。

優點:

  • 互斥可以讓你立刻醒來文件變得可用,而不是在等待平均50毫秒之後。
  • 互動讓你睡着一旦和醒來一次,而不是反覆睡覺/醒來。睡眠線程由操作系統非常高效地處理,幾乎不消耗任何資源。
  • 一旦你獲得了互斥鎖,打開的文件幾乎可能成功100%,而不是在成功之前失敗多次。

一切的一切,你不只是要更快,你很可能會在消費過程中更少的CPU週期

+0

您能否對上述代碼進行必要的更改? – Pankaj 2012-04-13 19:28:40

+2

@PankajGarg我相信我可以,但那會完成什麼?關於這種機制如何運作,有什麼不清楚的地方嗎? – 2012-04-13 19:32:01

+0

Branko; 下面是我們的一位架構師的狀態=>「我使用Mutex類的保留意見是,它的計算成本比使用鎖定語句或監視器類的計算成本要高得多,這不利於我們性能增強的目的。」有什麼想法嗎? – 2012-04-13 21:38:08

1

如果這是你做了很多事情(因此性能是一個問題),我會建議完全不同的設計。

你應該有一個公共的靜態方法(或一個單身的方法),它需要一個字符串(和一個文件名,如果這對多個文件有效)。在該方法中,它應該將該字符串放入BlockingCollection<string>。 (您可以通過Dictionary<string, BlockingCollection<string>>將文件名映射到該文件的隊列中,每個文件只有一個或一個文件。)

在大多數情況下(即緩衝區未滿),需要寫入內容的任務到一個文件只是將它添加到一個隊列,然後馬上恢復工作。

然後,您需要有一個單獨的線程/任務,它們只是從阻塞集合中讀取數據(即使您擁有大量阻塞集合,您也只需要一個)並將數據寫入文件。由於只有一個線程寫入文件,因此不需要鎖定文件IO,並且BlockingCollection被設計爲在此生產者/消費者模型中工作,並負責爲您提供所有需要的鎖定。

對於所有文件,我會建議只使用一個BlockingColleciton,除非您找到引人注目的性能原因來嘗試處理多個隊列。管理起來會容易得多。

+0

謝謝Servy。我忘了補充說我們的應用程序是一個.Net 3.5應用程序。 BlockingCollection是.Net 4.0的一部分。 – 2012-04-13 21:13:37

+0

@AjitGoel你可以用'ConcurrentQueue'完成所有的工作。這有點不方便,但你可以。 – Servy 2012-04-13 21:16:52

+0

ConcurrentQueue是.Net 4.0及以上版本?我不能在我們的應用程序中使用。 – 2012-04-13 21:36:49

相關問題