2013-03-06 49 views
1

我有一個幫助函數,它將XML文件反序列化,並從中生成c#對象。Asp.net MVC API基於方法參數鎖定函數

之後,將對象添加到服務器內存中。在服務器內存中添加內容的唯一方法是通過此功能。

public class DeserializeXmlHelper 
{ 
    public void DeserializeXml(Guid xml_Id, decimal version) 
    { 
     // heavy process here which takes about 3 seconds 
    } 
} 

此功能是由使用API​​方法(在Asp.net MVC API製造)不同的客戶端調用。

當調用API時,如果其他人已經使用相同的參數調用了相同的函數,我能否阻止該函數的執行?

這樣的事情,但我不知道這是否是一個好辦法。

public class DeserializeXmlHelper 
{ 
    private static readonly ConcurrentDictionary<string, object> _processes = new ConcurrentDictionary<string, object>(); 

    public void DeserializeXml(Guid xml_Id, decimal version) 
    { 
     string processKey = string.Format("{0}_v{1}", xml_Id, version.ToString("#0.0")); 
     object processLocker = null; 
     if (_processes.TryGetValue(processKey, out processLocker) == false) 
     { 
      processLocker = new object(); 
      _processes.TryAdd(processKey, processLocker); 
     } 

     lock (processLocker) 
     { 
      // heavy process here which takes about 3 seconds 

      _processes.TryRemove(processKey); 
     } 
    } 
} 

編輯 - 新版本

蒂姆·羅傑的答案是成功的工作。

但是,如果我只想在初始調用完成時返回,我可以做類似這樣的事情嗎? (我用ConcurrentDictionary,因爲我不知道怎麼加的鎖,但這個想法應該是相同的)

public class DeserializeXmlHelper 
{ 
    private static readonly ConcurrentDictionary<string, string> _processes = new ConcurrentDictionary<string, string>(); 
    public void DeserializeXml(Guid xml_Id, decimal version) 
    { 
     string _processKey = string.Format("{0}_v{1}", xml_Id, version.ToString("#0.0")); 
     string _processValue = null; 
     if (_processes.TryGetValue(_processKey, out _processValue) == true) 
     { 
      // function already called with the same parameters 
      do 
      { 
       System.Threading.Thread.Sleep(100); 
      } 
      while(_processes.TryGetValue(_processKey, out _processValue) == true) 

      return; 
     } 

     try 
     { 
      _processes.TryAdd(_processKey, _processValue); 

      var begin = "begin process"; 

      System.Threading.Thread.Sleep(10000); 

      var end = "ending process"; 
     } 
     finally 
     { 
      _processes.TryRemove(_processKey, out _processValue); 
     } 
    } 
} 
+1

如果參數相同,結果是否一樣? – 2013-03-06 13:36:44

+0

是的,對於相同的參數相同的結果 – Catalin 2013-03-06 13:37:39

+0

你可以使用緩存嗎?首先查看對象的緩存,以免每次都花費昂貴的代價?您可能會緩存來自Web API調用的整個結果。 – 2013-03-06 13:38:53

回答

0

你原來的解決方案並不遙遠,但你似乎總是在運行過程中不管當前狀態。

儘管您已經使用了一個併發字典,但您在更新其狀態時還需要一個鎖來鎖定整個字典,因爲線程可能會在TryGetValueAdd之間中斷。

private static readonly ConcurrentDictionary<string, object> _processes = new ConcurrentDictionary<string, object>(); 
private static readonly object _dictionaryLock = new object(); 

public void DeserializeXml(Guid xml_Id, decimal version) 
{ 
    string processKey = string.Format("{0}_v{1}", xml_Id, version.ToString("#0.0")); 
    object processLocker = null; 
    bool needsExecuting = false; 

    lock (_dictionaryLock) 
    { 
     if (_processes.TryGetValue(processKey, out processLocker) == false) 
     { 
      needsExecuting = true; 
      processLocker = new object(); 
      _processes.Add(processKey, processLocker); 
     } 
    } 

    lock (processLocker) 
    { 
     if (needsExecuting) 
     { 
      // heavy process here which takes about 3 seconds 

      _processes.Remove(processKey); 
     } 
    } 
} 
+0

當你檢查它是否包含密鑰時,如果有,從執行中返回:它不會等待原來的調用完成,它只是返回,對吧? – Catalin 2013-03-06 13:50:59

+0

是的,它只是返回,但你問「我可以阻止執行該功能...」 – 2013-03-06 13:54:44

+0

Exacly我想要的。它正在工作。我還有一個問題,我在問題主體中添加了它 – Catalin 2013-03-06 14:13:38