Asp.net MVC API锁定一个基于方法参数的函数
本文关键字:于方法 方法 参数 函数 一个 锁定 API net Asp MVC | 更新日期: 2023-09-27 18:02:46
我有一个辅助函数来反序列化XML文件,并从中生成c#对象。
之后,对象被添加到服务器内存中。在服务器内存中添加内容的唯一方法是通过此函数。
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);
}
}
}
编辑-新版本
Tim Roger的答案很成功。
但是,如果我想只在初始调用完成时返回,我可以这样做吗?(我使用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);
}
}
}
您的原始解决方案并不遥远,但无论当前状态如何,您似乎总是在运行该进程。
即使你已经使用了并发字典,你也需要一个锁来锁定整个字典,当你更新它的状态,因为线程可能在TryGetValue
和Add
之间被中断。
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);
}
}
}