【发布时间】:2022-06-10 20:08:02
【问题描述】:
我正在处理一段处理队列消息的代码(使用公共交通)。许多消息可以并行处理。所有消息都创建或修改 ActiveDirectory 中的对象(在这种情况下)。所有对象都需要根据 AD 架构定义进行验证。 (虽然它与问题无关,但我想指出,我们有很多客户在他们的 AD 架构中使用自定义扩展)
检索架构信息是一项缓慢的操作。我想做1次然后缓存它。但有许多并行处理消息。许多消息在第一个成功之前就开始获取模式信息。所以做了太多的工作。目前我用一个简单的信号量解决了这个问题。请参阅下面的代码。
但这不是一个好的解决方案,因为现在只有 1 个线程可以一直输入此代码。
我需要一些东西来为每个对象锁定代码 1 次并推迟其他请求,直到第一次检索和缓存完成。
什么样的构造可以让我做到这一点?
private static SemaphoreSlim _lock = new SemaphoreSlim(1, 1);
public ActiveDirectorySchemaObject? GetSchemaObjectFor(string objectClass)
{
//todo: create better solution
_lock.Wait();
try
{
if (_activeDirectorySchemaContainer.HasSchemaObjectFor(_scopeContext.CustomerId, objectClass) == false)
{
_logger.LogInformation($"Getting and caching schema from AD for {objectClass}");
_activeDirectorySchemaContainer.SetSchemaObjectFor(_scopeContext.CustomerId, objectClass, GetSchemaFromActiveDirectory(objectClass));
}
}
finally
{
_lock.Release();
}
return _activeDirectorySchemaContainer.GetSchemaObjectFor(_scopeContext.CustomerId, objectClass);
}
以下是问题的可能简化。简而言之。我正在寻找合适的结构来锁定一段代码,以便针对输入的每个变化进行并行访问。
评论提到了懒惰。我以前没用过的东西。但是阅读文档我看到它将对象的初始化推迟到以后。也许我可以为此重构。但是看看目前的代码,我似乎需要一个懒惰的“if”或一个懒惰的“函数”,但也许我过于复杂了。我发现考虑并行编程经常让我头疼。
【问题讨论】:
-
我可能会误解这种情况,但如果您已经加载了模式,您甚至不需要考虑信号量。一个只加载模式的线程似乎很有意义。
-
您考虑过使用
Lazy<T>类型吗? -
@DiplomacyNotWar 预加载信息的问题是我并行接收消息的队列在每条消息中都包含一个客户标识符。所以我事先不知道我需要从哪个客户那里加载什么。如果可以的话,我会改变它。但我不允许:(所以我需要在工作时防止多次加载和缓存尝试。
-
@TheodorZoulias 不,我没有。很抱歉,我对它不太熟悉。
标签: c# multithreading semaphore