锁定在一个实习字符串?

编程入门 行业动态 更新时间:2024-10-28 13:28:18
本文介绍了锁定在一个实习字符串?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

更新:如果这个方法不是线程安全的,但我想学习如何将使它线程安全的,是可以接受的。另外,我不想对单个对象锁定键的所有值如果我能避免它。

Update: It is acceptable if this method is not thread safe, but I'm interested in learning how I would make it thread safe. Also, I do not want to lock on a single object for all values of key if I can avoid it.

原题:假设我想写一个高阶函数,它接受一个键和功能,并检查对象是否被缓存给定的关键。如果有,则返回缓存的值。否则,给定的功能,运行和结果被高速缓存并返回

Original Question: Suppose I want to write a higher order function that takes a key and a function, and checks if an object has been cached with the given key. If is has, the cached value is returned. Otherwise, the given function is run and the result is cached and returned.

下面是我的代码的简化版本

Here's a simplified version of my code:

public static T CheckCache<T>(string key, Func<T> fn, DateTime expires) { object cache = HttpContext.Current.Cache.Get(key); //clearly not thread safe, two threads could both evaluate the below condition as true //what can I lock on since the value of "key" may not be known at compile time? if (cache == null) { T result = fn(); HttpContext.Current.Cache.Insert(key, result, null, expires, Cache.NoSlidingExpiration); return result; } else return (T)cache; }

此外,假设我不知道键在编译时。

我怎样才能使这个线程安全的?我知道我需要介绍到这里锁定,以防止1+从评估我的病情是真实的线程,但我不知道该怎么锁定。许多我读过有关锁定(如乔恩斯基特的文章)推荐使用的例子这是仅用于锁定虚拟私有变量。这是不可能在此情况下,由于密钥是在编译时未知的。我知道我可以平凡使这个线程安全由具有相同的锁用于每个键,但可能是浪费的。

How can I make this thread safe? I know I need to introduce locking here, to prevent 1+ threads from evaluating my condition as true, but I don't know what to lock on. Many of the examples I've read about locking (such as Jon Skeet's article) recommend using a "dummy" private variable that's used only for locking. This isn't possible in this case, because keys are unknown at compile time. I know I could trivially make this thread safe by having the same lock be used for every key, but that could be wasteful.

现在,我的主要问题是:

Now, my main question is:

是可以锁定在键?将字符串实习帮助在这里?

Is is possible to lock on key? Will string interning help here?

阅读的。NET 2.0字符串实习内而外,我知道我可以明确地调用中的String.intern()来获得1从字符串到字符串的实例的值1映射。 这是适用于锁定让我们改变上面的代码:

After reading .NET 2.0 string interning inside out, I understand that I can explicitly call String.Intern() to obtain a 1 to 1 mapping from the value of a string to instance of a string. Is this suitable to lock on? Let's change the above code to:

public static T CheckCache<T>(string key, Func<T> fn, DateTime expires) { //check for the scenario where two strings with the same value are stored at different memory locations key = String.Intern(key); lock (key) //is this object suitable for locking? { object cache = HttpContext.Current.Cache.Get(key); if (cache == null) { T result = fn(); HttpContext.Current.Cache.Insert(key, result, null, expires, Cache.NoSlidingExpiration); return result; } else return (T)cache; } }

是上面的实现线程安全的?

Is the above implementation thread safe?

推荐答案

与@ wsanville自己解决的问题,前部分提到的:

Problems with @wsanville's own solution, partly mentioned before:

  • 您的代码库的其他部分可能会锁用于不同目的同一实​​习字符串的情况下,只引起性能问题,如果幸运的话,和死锁如果运气不好(可能只在未来,随着代码库的增加,由程序员不知道你中的String.intern 的锁定格局正在扩展) - 注意,这包括在同一实习字符串的even如果他们是在不同的应用程序域 ,可能导致跨AppDomain的死锁
  • 它的不可能为你的情况下,收回实习内存你决定这样做
  • 中的String.intern()慢
  • other parts of your code base might lock on the same interned string instances for different purposes, causing only performance issues, if lucky, and deadlocks if unlucky (potentially only in the future, as the code base grows, being extended by coders unaware of your String.Intern locking pattern) - note that this includes locks on the same interned string even if they are in different AppDomains, potentially leading to cross-AppDomain deadlocks
  • it's impossible for you to reclaim the interned memory in case you decided to do so
  • String.Intern() is slow
  • 要解决所有这些问题3,你可以实现你自己的实习生() 你绑到您的具体锁定的目的,即不使用它作为一个通用的字符串interner 的:

    To address all these 3 issues, you could implement your own Intern() that you tie to your specific locking purpose, i.e. do not use it as a general-purpose string interner:

    private static readonly ConcurrentDictionary<string, string> concSafe = new ConcurrentDictionary<string, string>(); static string InternConcurrentSafe(string s) { return concSafe.GetOrAdd(s, String.Copy); }

    我称这种方法 ...安全() ,因为实习我不会存储在字符串传递实例时,因为这可能例如被一个已经扣留字符串,使得它受到上述1中提到的问题。

    I called this method ...Safe(), because when interning I will not store the passed in String instance, as that might e.g. be an already interned String, making it subject to the problems mentioned in 1. above.

    要比较性能实习的字符串不同的方式,我也试过以下2种方法,以及中的String.intern 。

    To compare the performance of various ways of interning strings, I also tried the following 2 methods, as well as String.Intern.

    private static readonly ConcurrentDictionary<string, string> conc = new ConcurrentDictionary<string, string>(); static string InternConcurrent(string s) { return conc.GetOrAdd(s, s); } private static readonly Dictionary<string, string> locked = new Dictionary<string, string>(5000); static string InternLocked(string s) { string interned; lock (locked) if (!locked.TryGetValue(s, out interned)) interned = locked[s] = s; return interned; }

    基准

    100线程,每个线程随机选择的5000不同的字符串(每片含8位)50000次,然后调用相应的方法实习生之一。充分暖机后的所有值。这是Windows 7中,64位,在4core I5​​。

    100 threads, each randomly selecting one of 5000 different strings (each containing 8 digits) 50000 times and then calling the respective intern method. All values after warming up sufficiently. This is Windows 7, 64bit, on a 4core i5.

    N.B。升温以上设置意味着升温后,将不会有任何的 的写入各自实习词典,但只读的。这是我很感兴趣的用例在手,但不同的读/写比率可能会影响效果。

    N.B. Warming up the above setup implies that after warming up, there won't be any writes to the respective interning dictionaries, but only reads. It's what I was interested in for the use case at hand, but different write/read ratios will probably affect the results.

    结果

    • 中的String.intern ():2032毫秒
    • InternLocked() 1245毫秒
    • InternConcurrent():458毫秒
    • InternConcurrentSafe():453毫秒
    • String.Intern(): 2032 ms
    • InternLocked(): 1245 ms
    • InternConcurrent(): 458 ms
    • InternConcurrentSafe(): 453 ms

    事实上, InternConcurrentSafe 是尽可能快地 InternConcurrent 似乎表明,字符串.Copy 是微不足道在经过时间的条款。

    The fact that InternConcurrentSafe is as fast as InternConcurrent seems to suggest that String.Copy is insignificant in terms of elapsed time.

    为正确封装这个,创建一个像类这样的:

    In order to properly encapsulate this, create a class like this:

    public class StringLocker { private readonly ConcurrentDictionary<string, string> _locks = new ConcurrentDictionary<string, string>(); public string GetLockObject(string s) { return _locks.GetOrAdd(s, String.Copy); } }

    和实例化一个接 StringLocker 你可能每个用例,它是作为调用

    and after instantiating one StringLocker for every use case you might have, it is as easy as calling

    lock(myStringLocker.GetLockObject(s)) { ...

    NB

    又在想,还有的无需返回类型的对象字符串 如果你想要做的是它锁定,所以复制的人物是完全不必要的,下面将执行比上面的类更好。

    Thinking again, there's no need to return an object of type string if all you want to do is lock on it, so copying the characters is totally unnecessary, and the following would perform better than above class.

    public class StringLocker { private readonly ConcurrentDictionary<string, object> _locks = new ConcurrentDictionary<string, object>(); public object GetLockObject(string s) { return _locks.GetOrAdd(s, k => new object()); } }

    更多推荐

    锁定在一个实习字符串?

    本文发布于:2023-06-04 19:05:20,感谢您对本站的认可!
    本文链接:https://www.elefans.com/category/jswz/34/503294.html
    版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
    本文标签:字符串

    发布评论

    评论列表 (有 0 条评论)
    草根站长

    >www.elefans.com

    编程频道|电子爱好者 - 技术资讯及电子产品介绍!