gpt4 book ai didi

c# - Parallel.ForEach 缺失/忽略/跳过/不添加对象

转载 作者:行者123 更新时间:2023-12-02 18:10:26 25 4
gpt4 key购买 nike

我的_baseBlockContainer.GetBaseBlocks();返回一个带有15317对象的ConcurrentQueue。为了进一步处理,我想按 Type 对它们进行排序。然而,它总是“错过”一些对象。

看来我的 Parallel.ForEach 不是线程安全的,因为 TypeConcurrentQueue 中的对象数量有时较少(对于 Type 来说,减少 1 到 250 个对象)比通过同步 foreach 排序时要好;但我不明白在哪里/为什么。

var baseBlocks = _baseBlockContainer.GetBaseBlocks();

var baseBlocksByTypeConcurrent = new ConcurrentDictionary<Type, ConcurrentQueue<BaseBlock>>();
// results of this always differ
Parallel.ForEach(baseBlocks, bb =>
{
if (!baseBlocksByTypeConcurrent.ContainsKey(bb.GetType()))
{
baseBlocksByTypeConcurrent[bb.GetType()] = new ConcurrentQueue<BaseBlock>();
}
baseBlocksByTypeConcurrent[bb.GetType()].Enqueue(bb);
});

var baseBlocksByType = new ConcurrentDictionary<Type, ConcurrentQueue<BaseBlock>>();
// results of this are always the same
foreach (var bb in baseBlocks)
{
if (!baseBlocksByType.ContainsKey(bb.GetType()))
{
baseBlocksByType[bb.GetType()] = new ConcurrentQueue<BaseBlock>();
}
baseBlocksByType[bb.GetType()].Enqueue(bb);
}

最佳答案

替换这个:

if (!baseBlocksByTypeConcurrent.ContainsKey(bb.GetType()))
{
baseBlocksByTypeConcurrent[bb.GetType()] = new ConcurrentQueue<BaseBlock>();
}
baseBlocksByTypeConcurrent[bb.GetType()].Enqueue(bb);

这样:

baseBlocksByTypeConcurrent.TryAdd(bb.GetType(), new ConcurrentQueue<BaseBlock>());
baseBlocksByTypeConcurrent[bb.GetType()].Enqueue(bb);

现有代码的问题是,如果 .ContainsKey 在多个线程中对于同一 block 类型同时求值为 false,那么它们都会设置与该类型相对应的值添加到新队列,从而删除该类型的任何现有队列。也就是说:ContainsKey 和索引器本身是线程安全的,但以您的方式单独使用时则不然。

TryAdd 是线程安全的,只会添加该键一次,而不是像分配给索引器那样重写它。

关于c# - Parallel.ForEach 缺失/忽略/跳过/不添加对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72443113/

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