【问题标题】:How can I populate a concurrent dictionary of sorted list?如何填充排序列表的并发字典?
【发布时间】:2012-02-23 18:54:07
【问题描述】:

假设我有这门课:

public class FileData
{
   public Weigth { get; set; } // Not the file size, but a business weight
   public Name { get; set; } // Name of the file
   public FullPath { get; set; } // full path of the file
}

我想从不同的网络位置探索一堆单独的文件夹。这个想法是能够在给定特定文件名的情况下检索所有候选文件,按文件的权重排序。

我想将每个文件夹的探索拆分到一个单独的线程中。在这种情况下,我的“商店”应该可以感知并发访问。

我尝试使用ConcurrentDictionary<string, SortedSet<CdlFileInfo>> 类来存储探索的结果。

但是,我对填充内部排序集的正确方法有点挣扎。

我试过了:

class Program 
{
    private readonly static ConcurrentDictionary<string, SortedSet<CdlFileInfo>> g_Files = new ConcurrentDictionary<string,SortedSet<CdlFileInfo>>();
    public static void Main()
    {
        PopulateFileList();

        // Do something with the list of files
    }
    private static void PopulateFileList()
    {
        var sources = AnyMethodToGetFoldersList(); // IEnumarable<string>
        sources.AsParallel().ForAll(x =>
        {
            Console.WriteLine("Enumerating files in {0}", x.Folder);
            var allFiles = Directory.GetFiles(x.Folder, "*.*", SearchOption.AllDirectories);

            foreach (var file in allFiles)
            {
                var fd = new FileData {
                    Weigth = GetWeigth(file), // returns a int... the method is not important
                    Name = Path.GetFileName(file),
                    FullPath = file
                };

                            // Here is the key piece of my code

                g_Files.AddOrUpdate(
                    fileName,
                    new SortedSet<FileData>() { fd },
                    (filePath, source) =>
                    {
                        g_Files[fileName].Add(fd);
                        return g_Files[fileName];
                    }
                );
            }
        });
    }

    public class FileData
    {
       public Weigth { get; set; } // Not the file size, but a business weight
       public Name { get; set; } // Name of the file
       public FullPath { get; set; } // full path of the file
    }
    public class FileDataWeightComparer : IComparer<CdlFileInfo>
    {
        public int Compare(FileData x, FileData y)
        {
            return Comparer<int>.Default.Compare(x.Weigth,y.Weigth);
        }
    }
}

此代码“似乎”有效。这是正确的方法吗?访问现有的 SortedSet 时,此代码是否可以防止线程问题?

此代码似乎不起作用。我可以看到一些找到的值丢失了。我怀疑AddOrUpdate 方法的最后一个参数没有正确锁定内部SortedSet。

【问题讨论】:

    标签: c# concurrency task-parallel-library


    【解决方案1】:

    更改这部分代码:

    (filePath, source) =>
    {
        g_Files[fileName].Add(fd);
        return g_Files[fileName];
    }
    

    到这里:

    (filePath,source) =>
    {
        source.Add(fd);
        return source;
    }
    

    【讨论】:

    • 好的。这解决了我一半的问题。实际上,使用SortedSet&lt;FileData&gt; 会产生副作用。由于我使用的是自定义比较器,因此该组每个重量值只能保存一个值。就我而言,几个项目可能具有相同的重量。我用一个简单的 List 替换了集合,它可以工作(不需要锁,因为外部 ConcurrentDictionary 为我管理锁。
    猜你喜欢
    • 2014-01-02
    • 1970-01-01
    • 2017-04-07
    • 1970-01-01
    • 2020-05-20
    • 1970-01-01
    • 1970-01-01
    • 2017-08-25
    • 1970-01-01
    相关资源
    最近更新 更多