Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 正在查字典。折衷是,在应用更新后(在后台线程上完成),需要复制和交换字典,但如果您不经常写入或在初始化过程中只写入一次,那么折衷绝对是值得的_C#_.net 4.0_Task Parallel Library_Concurrentdictionary - Fatal编程技术网

C# 正在查字典。折衷是,在应用更新后(在后台线程上完成),需要复制和交换字典,但如果您不经常写入或在初始化过程中只写入一次,那么折衷绝对是值得的

C# 正在查字典。折衷是,在应用更新后(在后台线程上完成),需要复制和交换字典,但如果您不经常写入或在初始化过程中只写入一次,那么折衷绝对是值得的,c#,.net-4.0,task-parallel-library,concurrentdictionary,C#,.net 4.0,Task Parallel Library,Concurrentdictionary,是什么使得单线程环境中的ConcurrentDictionary慢得多 使其在多线程环境中更快所需的机器开销 我的第一直觉是,lock(){}的速度总是比较慢。但显然不是 当没有竞争对手时,锁非常便宜。你可以每秒锁定一百万次,你的CPU甚至不会注意到,只要你是从一个线程执行的。多线程程序中影响性能的是锁的争用。当多个线程激烈竞争同一个锁时,几乎所有线程都必须等待持有锁的幸运线程释放锁。这就是带有细粒度锁定实现的ConcurrentDictionary的亮点所在。您拥有的并发性越多(处理器/内核越

是什么使得单线程环境中的
ConcurrentDictionary
慢得多

使其在多线程环境中更快所需的机器开销

我的第一直觉是,
lock(){}
的速度总是比较慢。但显然不是


当没有竞争对手时,
非常便宜。你可以每秒锁定一百万次,你的CPU甚至不会注意到,只要你是从一个线程执行的。多线程程序中影响性能的是锁的争用。当多个线程激烈竞争同一个
锁时,几乎所有线程都必须等待持有锁的幸运线程释放锁。这就是带有细粒度锁定实现的
ConcurrentDictionary
的亮点所在。您拥有的并发性越多(处理器/内核越多),它的光芒就越耀眼。

在一个线程中使用ConcurrentDictionary或在一个线程中同步访问都没有意义。当然,这本字典将击败ConcrurrentDictionary

这在很大程度上取决于使用模式和线程数。下面是一个测试,它表明ConcurrentDictionary在线程数增加时优于dictionary和lock

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;

namespace ConsoleApp
{

    class Program
    {

        static void Main(string[] args)
        {
            Run(1, 100000, 10);
            Run(10, 100000, 10);
            Run(100, 100000, 10);
            Run(1000, 100000, 10);
            Console.ReadKey();
        }

        static void Run(int threads, int count, int cycles)
        {
            Console.WriteLine("");
            Console.WriteLine($"Threads: {threads}, items: {count}, cycles:{cycles}");

            var semaphore = new SemaphoreSlim(0, threads);

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

            for (int i = 0; i < threads; i++)
            {
                Thread t = new Thread(() => Run(concurrentDictionary, count, cycles,  semaphore));
                t.Start();
            }

            Thread.Sleep(1000);

            var w = Stopwatch.StartNew();

            semaphore.Release(threads);

            for (int i = 0; i < threads; i++)
                semaphore.Wait();

            Console.WriteLine($"ConcurrentDictionary: {w.Elapsed}");

            var dictionary = new Dictionary<int, string>();
            for (int i = 0; i < threads; i++)
            {
                Thread t = new Thread(() => Run(dictionary, count, cycles, semaphore));
                t.Start();
            }

            Thread.Sleep(1000);

            w.Restart();

            semaphore.Release(threads);


            for (int i = 0; i < threads; i++)
                semaphore.Wait();

            Console.WriteLine($"Dictionary: {w.Elapsed}");

        }

        static void Run(ConcurrentDictionary<int, string> dic, int elements, int cycles, SemaphoreSlim semaphore)
        {
            semaphore.Wait();
            try
            {
                for (int i = 0; i < cycles; i++)
                    for (int j = 0; j < elements; j++)
                    {
                        var x = dic.GetOrAdd(i, x => x.ToString());
                    }
            }
            finally
            {
                semaphore.Release();
            }
        }

        static void Run(Dictionary<int, string> dic, int elements, int cycles, SemaphoreSlim semaphore)
        {
            semaphore.Wait();
            try
            {
                for (int i = 0; i < cycles; i++)
                    for (int j = 0; j < elements; j++)
                        lock (dic)
                        {
                            if (!dic.TryGetValue(i, out string value))
                                dic[i] = i.ToString();
                        }
            }
            finally
            {
                semaphore.Release();
            }
        }
    }
}
使用系统;
使用System.Collections.Concurrent;
使用System.Collections.Generic;
使用系统诊断;
使用系统线程;
名称空间控制台
{
班级计划
{
静态void Main(字符串[]参数)
{
运行(1,100000,10);
运行(10,100000,10);
运行(100、100000、10);
运行(1000、100000、10);
Console.ReadKey();
}
静态无效运行(int线程、int计数、int周期)
{
控制台。写线(“”);
WriteLine($“Threads:{Threads},items:{count},cycles:{cycles}”);
var信号量=新信号量lim(0,线程);
var concurrentDictionary=新建concurrentDictionary();
对于(int i=0;iRun(concurrentDictionary、count、cycles、信号量));
t、 Start();
}
睡眠(1000);
var w=秒表.StartNew();
信号量释放(线程);
对于(int i=0;iRun(字典、计数、循环、信号量));
t、 Start();
}
睡眠(1000);
w、 重启();
信号量释放(线程);
对于(int i=0;ix.ToString());
}
}
最后
{
semaphore.Release();
}
}
静态无效运行(字典dic、int元素、int循环、信号量LIM信号量)
{
semaphore.Wait();
尝试
{
对于(int i=0;i
线程数:1,项目数:100000,周期数:10 ConcurrentDictionary:00:00.0000499 字典:00:00:00.0000137

线程数:10,项目数:100000,周期数:10 ConcurrentDictionary:00:00.0497413 字典:00:00:00.2638265

线程数:100,项目数:100000,周期数:10 ConcurrentDictionary:00:00.2408781 字典:00:00:02.2257736

线程:1000个,项目:100000个,周期:10个 ConcurrentDictionary:00:00.8196668
字典:00:00:25.5717232

首先,您是否在未连接调试器的情况下以发布模式运行测试?(即“无调试运行”)。其次,“每个线程负责自己的链表”是不正确的。如果您想了解这些东西是如何实现的,请从下载库源代码。确保所有操作都是原子操作会带来开销。当操作本身非常简单时(在
字典
的情况下,它只设置一个数组值,几乎没有其他内容),相比之下,开销可能会很大。与非平凡操作相比,开销更可能可以忽略不计。@JimMischel这只适用于
ConcurrentBag
,这与您提到的其他集合完全不同。例如,
ConcurrentQueue
,不能以相同的方式实现,因为这样就不是FIFO了。而
ConcurrentStack
也不是后进先出。我想你的推理是,“我可以自己用锁来做这件事,也可以用专家编写的ConcurrentDictionary来做。因为专家们也可以选择使用锁,当然他们的实现
baseline = 00:00:01.2604656
baseline = 00:00:00.3229741
        Stopwatch sw = new Stopwatch();      
        sw.Start();
        var d = new ConcurrentDictionary<int, int>();
        for (int i = 0; i < 1000000; i++) d[i] = 123;
        for (int i = 1000000; i < 2000000; i++) d[i] = 123;
        for (int i = 2000000; i < 3000000; i++) d[i] = 123;
        sw.Stop();
        Console.WriteLine("baseline = " + sw.Elapsed);



        sw.Start();
        var d2 = new Dictionary<int, int>();
        for (int i = 0; i < 1000000; i++) lock (d2) d2[i] = 123;
        for (int i = 1000000; i < 2000000; i++) lock (d2) d2[i] = 123;
        for (int i = 2000000; i < 3000000; i++) lock (d2) d2[i] = 123;
        sw.Stop();
        Console.WriteLine("baseline = " + sw.Elapsed);

        sw.Stop();
|          Method |        Mean |     Error |    StdDev |    Gen 0 |    Gen 1 |    Gen 2 | Allocated |
|---------------- |------------:|----------:|----------:|---------:|---------:|---------:|----------:|
| ConcurrentWrite | 1,372.32 us | 12.752 us | 11.304 us | 226.5625 |  89.8438 |  44.9219 | 1398736 B |
|        COWWrite | 1,077.39 us | 21.435 us | 31.419 us |  56.6406 |  19.5313 |  11.7188 |  868629 B |
|       DictWrite |   347.19 us |  5.875 us |  5.208 us | 124.5117 | 124.5117 | 124.5117 |  673064 B |
|  ConcurrentRead |    63.53 us |  0.486 us |  0.431 us |        - |        - |        - |         - |
|         COWRead |    81.55 us |  0.908 us |  0.805 us |        - |        - |        - |         - |
|        DictRead |    70.71 us |  0.471 us |  0.393 us |        - |        - |        - |         - |
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;

namespace ConsoleApp
{

    class Program
    {

        static void Main(string[] args)
        {
            Run(1, 100000, 10);
            Run(10, 100000, 10);
            Run(100, 100000, 10);
            Run(1000, 100000, 10);
            Console.ReadKey();
        }

        static void Run(int threads, int count, int cycles)
        {
            Console.WriteLine("");
            Console.WriteLine($"Threads: {threads}, items: {count}, cycles:{cycles}");

            var semaphore = new SemaphoreSlim(0, threads);

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

            for (int i = 0; i < threads; i++)
            {
                Thread t = new Thread(() => Run(concurrentDictionary, count, cycles,  semaphore));
                t.Start();
            }

            Thread.Sleep(1000);

            var w = Stopwatch.StartNew();

            semaphore.Release(threads);

            for (int i = 0; i < threads; i++)
                semaphore.Wait();

            Console.WriteLine($"ConcurrentDictionary: {w.Elapsed}");

            var dictionary = new Dictionary<int, string>();
            for (int i = 0; i < threads; i++)
            {
                Thread t = new Thread(() => Run(dictionary, count, cycles, semaphore));
                t.Start();
            }

            Thread.Sleep(1000);

            w.Restart();

            semaphore.Release(threads);


            for (int i = 0; i < threads; i++)
                semaphore.Wait();

            Console.WriteLine($"Dictionary: {w.Elapsed}");

        }

        static void Run(ConcurrentDictionary<int, string> dic, int elements, int cycles, SemaphoreSlim semaphore)
        {
            semaphore.Wait();
            try
            {
                for (int i = 0; i < cycles; i++)
                    for (int j = 0; j < elements; j++)
                    {
                        var x = dic.GetOrAdd(i, x => x.ToString());
                    }
            }
            finally
            {
                semaphore.Release();
            }
        }

        static void Run(Dictionary<int, string> dic, int elements, int cycles, SemaphoreSlim semaphore)
        {
            semaphore.Wait();
            try
            {
                for (int i = 0; i < cycles; i++)
                    for (int j = 0; j < elements; j++)
                        lock (dic)
                        {
                            if (!dic.TryGetValue(i, out string value))
                                dic[i] = i.ToString();
                        }
            }
            finally
            {
                semaphore.Release();
            }
        }
    }
}