添加 Parallel.Foreach 结果在迭代完成时做一个字典

Adding Parallel.Foreach results do a dictionary when iteration completes

我在这里阅读了一些链接,但我无法找到问题的答案。

我想要实现的是将 Parallel.ForEach 的结果添加到 ConcurrentDictionary 中。但是,我如何确定我添加的是迭代结果而不是空值?

我的意思是:我想在操作完成后添加变量。我担心我可能会添加一个空值(即:向集合中添加一个不完整的迭代)。

我的代码在下面。 感谢您的任何提示。

我也读过有关使用锁比 ConcurrentDictionary 更快的信息,但我认为在我的情况下它不会产生显着差异。

提前致谢。

public Dictionary<string,IMagickImage> ComposedImages { get; private set; }
        public ParallelImageComposer(Dictionary<string,MagickImage> InputImages, MagickImage InkZoneImage, int OrientationNumber)
        {

            var resultCollection = new ConcurrentDictionary<string, IMagickImage>();            
            Parallel.ForEach(InputImages, CurrentKeyValuePair =>
            {
                var img = new ImageComposer(InkZoneImage, CurrentKeyValuePair.Value, OrientationNumber).ComposedImage;
                resultCollection.TryAdd(CurrentKeyValuePair.Key, img);
            });            
            ComposedImages = resultCollection.ToDictionary(x => x.Key, x => x.Value);  

据70-483考试参考:


使用并发集合

在多线程环境中工作时,您需要确保不会在没有同步访问的情况下同时操作共享数据。 .NET Framework 提供了一些专为在并发环境中使用而创建的集合 类,这就是您在使用多线程时所拥有的。 这些集合是线程安全的,这意味着它们在内部使用同步来确保它们可以同时被多个线程访问。

这些合集如下: - 阻塞集合

  • 并发包

  • ConcurrentDictionary

  • 并发队列

  • 并发堆栈

  • ConcurrentDictionary

ConcurrentDictionary 以线程安全的方式存储键值对。您可以使用方法来添加和删除项目,并在项目存在时更新项目。

显示您可以在 ConcurrentDictionary 上使用的方法

var dict = new ConcurrentDictionary<string, int>();

if (dict.TryAdd("k1", 42))
{
    Console.WriteLine("Added");
}

if (dict.TryUpdate("k1", 21, 42))
{
    Console.WriteLine("42 updated to 21");
}

dict["k1"] = 42; // Overwrite unconditionally
int r1 = dict.AddOrUpdate("k1", 3, (s, i) => i * 2);
int r2 = dict.GetOrAdd("k2", 3);

在使用 ConcurrentDictionary 时,您有可以原子添加的方法, 获取和更新项目。原子操作意味着它将作为一个步骤开始和完成,而不会受到其他线程的干扰。 TryUpdate 在更新之前检查当前值是否等于现有值。 AddOrUpdate 确保添加一个项目(如果不存在),如果存在则更新为新值。 GetOrAdd 获取项目的当前值(如果可用);如果没有,它会使用工厂方法添加新值。


所以,为了确保您添加了迭代的结果,我会写这样的东西,并且可能会测试我的方法的 return。

public ConcurrentDictionary <string,IMagickImage> ParallelImageComposer(Dictionary<string,MagickImage> InputImages, MagickImage InkZoneImage, int OrientationNumber)
{
    var resultCollection = new ConcurrentDictionary <string,IMagickImage>();

    Parallel.ForEach(InputImages, CurrentKeyValuePair =>
    {
        var img = new ImageComposer(InkZoneImage, CurrentKeyValuePair.Value, OrientationNumber).ComposedImage;

        resultCollection.TryAdd(CurrentKeyValuePair.Key, img);
    });

    return resultCollection;
}