.net - 使用字典时 .NET 4 并发性能差

标签 .net c#-4.0 data-structures concurrency

我正在尝试将一些带有字符串键的数据存储到字典中。 数据非常大,例如数千万个字符串。 因此,我决定开发并发版本,以实现更快的执行速度。 然而,并发版本的性能非常糟糕。

我用过两种策略:
1- 将输入分成两个 block ,并使用两个并发线程将每个 block 插入到两个不同的字典中。
2- 使用 Parallel.ForEach 调用将整个数据插入 ConcurrentDictionary。

但不幸的是,这两种策略的表现并不乐观。 第一种策略大约好于 20~30% 这还不够,因为任务之间没有共享数据。 而且,并发收集大约慢 100%!

现在我想知道问题是什么?????? 这是否意味着在这个问题上没有并行加速的机会??? 如果有人能帮助我,我将不胜感激:)

我在下面附上了示例代码。
在我的双核 AMD Turion 系统上,示例结果是(以毫秒为单位):
初始化:542
序号:294
并行:234
并发 Dic:666

    static void Main(string[] args)
    {
        System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
        watch.Start();
        Random r = new Random();
        int count=1000000;
        string[] list = new string[count];
        for (int i = 0; i < count; i++)
        {
            list[i] = r.Next(10000).ToString();
        }

        watch.Stop();
        Console.WriteLine("Initialization: "+watch.ElapsedMilliseconds);
        watch.Reset();
        watch.Start();

        Dictionary<string, byte> dic1 = new Dictionary<string, byte>();
        Dictionary<string, byte> dic2 = new Dictionary<string, byte>();
        foreach (var s in list)
            dic1[s] = 0;

        watch.Stop();
        Console.WriteLine("Serial: " + watch.ElapsedMilliseconds);
        watch.Reset();
        watch.Start();


        dic1.Clear();

        Task t1 = new Task(
            () =>
            {
                for (int i = 0; i < list.Length / 2; i++)
                    dic1[list[i]] = 1;
            }
            );
        Task t2 = new Task(
            () =>
            {
                for (int i = list.Length / 2; i < list.Length; i++)
                    dic2[list[i]] = 1;
            }
            );

        t1.Start();
        t2.Start();
        Task.WaitAll(t1, t2);

        watch.Stop();
        Console.WriteLine("Parallel: " + watch.ElapsedMilliseconds);
        watch.Reset();
        watch.Start();

        ConcurrentDictionary<string, byte> dicp = new ConcurrentDictionary<string, byte>();
        Parallel.ForEach(list, s =>
            {
                dicp.AddOrUpdate(s, 1, (k, v) => v);
            }
        );

        watch.Stop();
        Console.WriteLine("Concurrent Dic: " + watch.ElapsedMilliseconds);
        watch.Reset();
        watch.Start();

        Console.ReadKey();

        return;

    }

最佳答案

ConcurrentDictionary 变慢很容易解释:访问任何条目都需要锁。它不适用于重负载。

很难解释为什么第一个基于 Task 的基准测试没有看到显着的加速。它应该有。您在几乎没有同步的情况下正确地划分了工作。

也许任务的一次性启动成本约为 100 毫秒?尝试在循环中重复基准测试 10 次。上次运行的结果是否相同?

尝试创建新词典。重用旧测试从旧测试中继承状态:一个预先确定大小的内部数组。

HansPassant 在评论中提到您可能受内存带宽限制。我认为情况并非如此。 Dictionary 在内部进行一些不太便宜的计算,现代系统的带宽限制不多。它们可能受延迟限制,但不受带宽限制。

关于.net - 使用字典时 .NET 4 并发性能差,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11926231/

相关文章:

.net - 通用类 (T) - 从一系列类型 VB.Net 中指定

c# - 将 .net 4.0 中的 Entity Framework 与 Oracle 数据库一起使用 - 可能吗?

所有其他应用程序上的 C# 气球通知弹出窗口

c# - ASP.NET Resourcemanager读取本地.resx

c - C 语言的拼写检查器

.net - 如何检测由于 Windows 7 幻灯片放映而导致的墙纸变化?

c# - 如何在带有插件的应用程序中使用版本号作为接口(interface)?

c# - 将子类转换为其通用祖 parent 类

algorithm - t(n)=2t(n/2)+n^0.5/logn 可以用大师定理求解吗?

C++ 基于文本的游戏 - "Map"实现