不可变的数据结构和并发性

Ben*_*Ben 4 c# concurrency immutability

我试图理解在并发编程中使用不可变数据结构如何可以避免锁定的需要.我在网上看过一些内容,但还没有看到任何具体的例子.

例如,假设我们有一些使用锁定的代码(C#)Dictionary< string, object>执行此操作:

class Cache
{
    private readonly Dictionary<string, object> _cache = new Dictionary<string, object>();
    private readonly object _lock = new object();

    object Get(string key, Func<object> expensiveFn)
    {
        if (!_cache.ContainsKey("key"))
        {
            lock (_lock)
            {
                if (!_cache.ContainsKey("key"))
                    _cache["key"] = expensiveFn();
            }
        }
        return _cache["key"];
    }
}
Run Code Online (Sandbox Code Playgroud)

如果_cache是不可变的,那怎么样?是否可以删除lock并确保expensiveFn不会多次调用?

Bra*_*ner 9

简短的回答是,它没有,至少不完全.

Immutability只保证在您使用它时,另一个线程无法修改数据结构的内容.一旦有了实例,该实例永远不会被修改,因此您将始终安全地阅读它.任何编辑都需要制作实例的副本,但这些副本不会直接干扰已引用的任何实例.

在多线程应用程序中,即使使用不可变对象,仍然有很多理由需要锁定和同步构造.它们主要处理与时间相关的问题,例如竞争条件,或控制线程流,以便在正确的时间进行活动.不可变对象实际上无法帮助解决这些问题.

不变性使多线程更容易,但它并不容易.


至于你关于什么是不可变字典的问题.我不得不说,在大多数情况下,在你的例子中,甚至使用不可变字典也没有多大意义.因为它被用作"活动"对象,随着项目的添加和删除而固有地变化.即使是围绕不变性设计的语言,如F#,也有可变对象用于此目的.有关详细信息,请参阅此链接.可以在这里找到不可变版本.