每个 Web 请求的唯一锁定对象

本文关键字:锁定 对象 唯一 Web 请求 每个 | 更新日期: 2023-09-27 18:34:43

我正在构建一个WCF翻译服务。该服务使用谷歌翻译的网络API。为了避免重新获取经常搜索的查询,该服务会保留上次搜索的内存缓存。搜索功能首先检查缓存,然后才向谷歌发出请求。最后一个重要细节 - 每次请求到达时,我都会构造一个字符串作为它的关键 - 它由搜索词和两种语言的名称代码组成 - 因此每个特定搜索都是唯一的。

问题是这样的:假设两个确切的请求同时到达,我想将第二个请求锁定在整个搜索功能之外,以便当它进入时,它将找到第一个已经输入到缓存中的搜索结果。如果收到不同的请求,我想让它进来。

的想法是使用我构造的字符串放置一个锁,因为它在每个精确搜索中都是唯一的(相同的搜索词,相同的语言(。这会给出我描述的结果吗?

感谢您阅读本文(:

请参阅下面的代码示例 - 再次感谢!

public async Task<TranslationResult> TranslateAsync(Langueges From, Langueges To, string Content)
{
   string key = Content + From.ToString() + To.ToString();
   lock(key)
   {
      //look for the search result in the cache
      //if not found, request from google and store result in the memory cache
   }
}

每个 Web 请求的唯一锁定对象

像这样的东西?

// this cache is probably going to be the application level cache in asp.net
// but using Dictionary as an example in this case
Dictionary<string,TranslationResult> cache = new ...
private static object syncRoot = new Object();
if (!cache.ContainsKey(key)
{
    lock(syncRoot)
    {
        // this double checks is not a mistake.
        // the second request would check for existence of
        // the key once it acquire the lock
        if (!cache.ContainsKey(key) {
            // send request to google then store the result 
        }
        else {
            return cache[key];
        }
    }
}
else
{
    return cache[key];
}

我认为您不会得到所需的行为:变量"key"将始终是新创建的对象,并且当前线程将始终立即被授予锁定。 我不相信字符串实习会在这里发挥作用,因为"键"变量不是文字。 如果"key"是一个被扣留的字符串,那么它可能会像你想要的那样工作,但这将是一个奇怪的副作用。

怎么办? 请考虑使用 ConcurrentDictionary.GetOrAdd 方法。 您的"key"变量将成为key参数。 如果键不在缓存中,则将调用 valueFactory。 您的值工厂实现应该将调用发送到 Google。 这是 ConcurrentDictionary 是线程安全的,因此您不需要显式锁定。

如果两个确切的请求同时到达,则返回其中一个原始:)您可以知道哪个没有被修剪,然后再次发送。我以前是这样做的