我需要基于单个查询参数,一次不允许对 API 进行多次调用。必须允许使用不同查询参数值的并行调用。
我通过
调用apiawait client.GetAsync(QueryHelpers.AddQueryString(path, parameters))
因此,有一个异步调用不允许我使用 System.Threading.Monitor.TryEnter 因为当我尝试释放锁时出现异常:
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))
您可以保留所有“锁定”的 id 列表,如下所示:
private HashSet<long> lockedIds = new();
public async Task ExclusiveAccessById(long id)
{
bool hasExclusiveAccess = true;
lock (lockedIds)
{
hasExclusiveAccess = lockedIds.Add(id);
}
try
{
if (!hasExclusiveAccess)
{
// handle failure
return;
}
// Handle success
await Task.Delay(1);
return;
}
finally
{
lock (lockedIds)
{
lockedIds.Remove(id);
}
}
}
这里的关键部分是在实际方法运行时或执行任何等待等操作时不要持有锁。您可能可以使用 ConcurrentDictionary 执行类似的操作,但如果争用较少,则锁的开销应该很低。