DotNet高性能设备索引实现(多线程安全+效率)

Posted 何以解忧 `唯有暴富

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DotNet高性能设备索引实现(多线程安全+效率)相关的知识,希望对你有一定的参考价值。

代码下载地址

https://download.csdn.net/download/g313105910/18464759

多线程通过字典进行设备查找,主键key使用Guid,也可以用设备唯一Id去替换,最关键的是string,string是不可变字符对象(多线程安全+效率:只用复制地址)

首先先讲一下string

string和String效果相同,MSDN中对string的说明:string is an alias for String in the .NET Framework。string是String的别名而已,string是c#中的类,String是Framework的类,C# string 映射为 Framework的 String。如果用string,编译器会把它编译成String,所以如果直接用String就可以让编译器少做一点点工作。

为什么String是不可变字符对象呢?有什么好处呢? 不可变对象,顾名思义就是创建后不可以改变的对象。

String s = “ABC”; s.toLowerCase(); 如上s.toLowerCase()并没有改变“ABC“的值,而是创建了一个新的String类“abc”,然后将新的实例的指向变量s。 相对于可变对象,不可变对象有很多优势:

1).不可变对象可以提高String Pool的效率和安全性。如果你知道一个对象是不可变的,那么需要拷贝这个对象的内容时,就不用复制它的本身而只是复制它的地址,复制地址(通常一个指针的大小)需要很小的内存效率也很高。对于同时引用这个“ABC”的其他变量也不会造成影响。

2).不可变对象对于多线程是安全的,因为在多线程同时进行的情况下,一个可变对象的值很可能被其他进程改变,这样会造成不可预期的结果,而使用不可变对象就可以避免这种情况。 String是所有语言中最常用的一个类。我们知道在Java中,String是不可变的、final的。Java在运行时也保存了一个字符串池(String pool),这使得String成为了一个特别的类。

测试程序的流程图

代码 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadTest
{
    class Program
    {
        static string GuidStr = "";
        static Dictionary<string, DataCache> Datas = new Dictionary<string, DataCache>();
        static void Main(string[] args)
        {
            List<Thread> threads = new List<Thread>();
            for (int i = 0; i < 10000; i++)
            {
                GuidStr = Guid.NewGuid().ToString();
                DataCache dataCache = new DataCache() { Name = GuidStr, Value = "123456789" };
                DataCache tempDataCache;
                if (Datas.TryGetValue(GuidStr, out tempDataCache))
                {
                    Datas[GuidStr] = dataCache;
                }
                else
                {
                    Datas.Add(GuidStr, dataCache);
                }
            }
            for (int i = 0; i < 1000; i++)
            {
                Thread thread = new Thread(Check);
                thread.Start();
                threads.Add(thread);
            }

            for (int i = 0; i < 10; i++)
            {
                Thread thread = new Thread(Amend);
                thread.Start();
                threads.Add(thread);
            }

            Thread.Sleep(10000);

            foreach(var thread in threads)
            {
                try
                {
                    thread.Abort();
                }
                catch(Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
            Console.WriteLine("Exit");
        }

        public static void Amend()
        {
            while(true)
            {
                DataCache dataCache = Get(GuidStr);
                if (dataCache != null)
                {
                    dataCache.Value = "123456789";
                }
                Thread.Sleep(1000);
                if (dataCache != null)
                {
                    dataCache.Value = "987654321";
                }
                Thread.Sleep(1000);
                if (dataCache != null)
                {
                    dataCache.IsDelete = true;
                }
                Thread.Sleep(1000);
                if (dataCache != null)
                {
                    dataCache.IsDelete = false;
                }
                Thread.Sleep(1000);
            }
        }

        public static void Check()
        {
            while (true)
            {
                DataCache dataCache = Get(GuidStr);
                if (dataCache != null)
                {
                    if(dataCache.IsDelete == true)
                    {
                        Console.WriteLine("IsDelete == True");
                    }
                    else
                    {
                        if (dataCache.Value == "123456789")
                        {
                            Console.WriteLine("IsDelete == False,Value == 123456789");
                        }
                        else if (dataCache.Value == "987654321")
                        {
                            Console.WriteLine("IsDelete == False,Value == 987654321");
                        }
                        else
                        {
                            Console.WriteLine("Error");
                        }
                    }
                }
                else
                {
                    Console.WriteLine("dataCache == null");
                }
                Thread.Sleep(10);
            }
        }

        public static DataCache Get(string guidStr)
        {
            DataCache dataCache;
            if (Datas.TryGetValue(guidStr, out dataCache))
            {
                return dataCache;
            }
            else
            {
                return null;
            }
        }
    }

    public class DataCache
    {
        public string Name { get; set; }
        public string Value { get; set; }
        public bool IsDelete { get; set; }
        //public String Value { get; set; }
    }
}

 

以上是关于DotNet高性能设备索引实现(多线程安全+效率)的主要内容,如果未能解决你的问题,请参考以下文章

VectorArrayListLinkedList在存储结构和存取性能上的区别

dotnet ConcurrentDictionary 的 GetOrAdd 性能比 TryGetValue 加 TryAdd 低

十二ConcurrentHashMap的实现原理解析

2 ArrayList 详解

Java容器

WPF 支持的多线程 UI 并不是线程安全的