gpt4 book ai didi

.net - 可以递归调用 ConcurrentDictionary.GetOrAdd() 吗?

转载 作者:行者123 更新时间:2023-12-03 15:13:10 25 4
gpt4 key购买 nike

ConcurrentDictionary.GetOrAdd(TKey, Func<TKey, TValue>)接受工厂函数以允许将项目的延迟实例化放入字典中。

定义一个本身调用 GetOrAdd() 的工厂函数是否安全,即在“父”GetOrAdd() 的上下文中调用 GetOrAdd。

以下代码演示了该模式;它似乎确实有效,但它安全吗?

class Program
{
static ConcurrentDictionary<string,object> __dict = new ConcurrentDictionary<string, object>();

static void Main(string[] args)
{
Foo foo = GetOrAddFoo();
Console.WriteLine(foo._name);
Console.WriteLine(foo._bar._name);
Console.ReadKey();
}

static Bar GetOrAddBar()
{
Console.WriteLine("GetOrAddBar: enter");
Func<string,Bar> factoryFn = (x) => LoadBar(x);
Bar bar = __dict.GetOrAdd("bar", factoryFn) as Bar;
Console.WriteLine("GetOrAddBar: exit");
return bar;
}

static Foo GetOrAddFoo()
{
Console.WriteLine("GetOrAddFoo: enter");
Func<string,Foo> factoryFn = (x) => LoadFoo(x);
Foo foo = __dict.GetOrAdd("foo", factoryFn) as Foo;
Console.WriteLine("GetOrAddFoo: exit");
return foo;
}

static Bar LoadBar(string name)
{
Bar bar = new Bar();
bar._name = name;
return bar;
}

static Foo LoadFoo(string name)
{
Foo foo = new Foo();
foo._name = name;
foo._bar = GetOrAddBar();
return foo;
}

public class Foo
{
public string _name;
public Bar _bar;
}

public class Bar
{
public string _name;
}
}

最佳答案

答案是肯定的,绝对安全。仅当给定键尚不存在时才调用值函数。以下是引擎盖下发生的事情的演练。

演练

首先我们假设字典是完全空的,为了简单起见,我只会以数组格式显示键:

dictionary = []

首次执行 GetOrAddFoo方法,“Foo”键不存在,因此字典调用值函数,在此调用中是 LoadFoo方法。字典在这里仍然是空的。
dictionary = []
LoadFoo内部调用 GetOrAddBar ,它检查并发现“Bar”键不存在,所以 LoadBar调用 value 函数并返回创建的“Bar”条目。此时的字典如下所示:
dictionary = ["Bar"]

此时的字典中包含项目“Bar”。我们还没有完成 LoadFoo值(value)函数,但它现在会。
dictionary = ["Bar"]
LoadFoo方法重新获得控制权并返回 Foo要存储在字典中的对象。之后 LoadFoo完成, GetOrAddFoo也可以完成。我们现在的字典看起来像这样:
dictionary = ["Bar", "Foo"]
GetOrAddFoo 的 future 电话

在随后调用 GetOrAddFoo 时,字典中已有 Foo 的条目因此不会调用它的值函数,甚至不会调用 Bar值(value)函数。它立即返回。
dictionary = ["Bar", "Foo"]

但是如果我们删除 Bar 会发生什么?从字典中,然后调用 GetOrAddFoo ?假设我们确实删除了它,让我们的字典像这样:
dictionary = ["Foo"]

现在我们调用 GetOrAddFoo再次。 Foo仍然存在,所以字典不会调用 LoadFoo值(value)函数。因此, Bar不会重新添加到字典中。我们的字典保持不变:
dictionary = ["Foo"]

如果我们调用 GetOrAddBar不过,直接,我们将在那时添加“Bar”。
dictionary = ["Foo", "Bar"]

在并发字典的 Get-Or-Add 方法的底层

在引擎盖下,随时 GetOrAdd方法被调用时,首先检查给定键的存在。

如果此时它不存在,则调用值函数。在 value 函数返回后,在字典上放置一个锁以允许添加新条目。

在多线程世界中,我们可以有 2 个线程尝试将相同的确切键添加到字典中。字典会运行 value 函数,然后尝试获取锁,获取锁后,检查 key 是否再次存在。

这样做的原因是在锁定检索时,另一个线程可能会加入并添加相同的 key 。原始线程在收到锁后需要检查这种情况,以免最终导致键冲突。

关于.net - 可以递归调用 ConcurrentDictionary.GetOrAdd() 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40590002/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com