2013-03-06 45 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