提问人:GIovanni 提问时间:11/14/2023 更新时间:11/15/2023 访问量:52
不允许基于参数的并行 API 调用
Don't allow parallel API invocation based on parameter
问:
基于单个查询参数,我要求一次不允许对 API 进行多次调用。必须允许使用不同值的查询参数进行并行调用。
我通过
await client.GetAsync(QueryHelpers.AddQueryString(path, parameters))
因此,有一个异步调用不允许我使用 System.Threading.Monitor.TryEnter beacause 当我尝试释放锁时出现异常:
System.Threading.SynchronizationLockException:从不同步的代码块调用对象同步方法。
这是代码片段
try
{
Monitor.TryEnter(lockObj, timeout, ref lockTaken);
if (lockTaken)
{
List<PatientData> patients = await RetrievePatientsDataAsync(client, new Dictionary<string, string>
{
["customerNo"] = customerNo,
["offset"] = _lindeAPIOptions.Offset,
["pagesize"] = _lindeAPIOptions.Pagesize
});
data.Patients = patients;
return data;
}
}
finally
{
// Ensure that the lock is released.
if (lockTaken)
{
Monitor.Exit(lockObj);
}
}
参数为 customerNo。在方法 RetrievePatientsDataAsync 中,我调用上述
await client.GetAsync(QueryHelpers.AddQueryString(path, parameters))
答:
1赞
JonasH
11/14/2023
#1
您可以保留所有“锁定”的 ID 列表,如下所示:
private HashSet<long> lockedIds = new();
public async Task ExclusiveAccessById(long id)
{
bool hasExclusiveAccess = true;
lock (lockedIds)
{
hasExclusiveAccess = lockedIds.Add(id);
}
if (!hasExclusiveAccess)
{
// handle failure
return;
}
try
{
// Handle success
await Task.Delay(1);
return;
}
finally
{
lock (lockedIds)
{
lockedIds.Remove(id);
}
}
}
这里的关键部分是在实际方法运行时或执行任何等待等操作时不要按住锁。您可能可以对 ConcurrentDictionary 执行类似操作,但如果争用率较低,则锁的开销应该很低。
评论
1赞
JonasH
11/14/2023
@TheodorZoulias Oups,你的权利,检查应该在尝试/最终之前。
0赞
GIovanni
11/15/2023
比你。我已经实现了一个包含 HashSet 的线程安全单例,然后它就可以工作了。
评论
lock