当前位置:首页 > C#编程 > C#/.net框架 > 正文内容

C# .net 集合-并发处理(List集合换成ConcurrentQueue、ConcurrentDictionary )

秋天2年前 (2022-05-09)C#/.net框架643

 

背景 
List集合,数组Int[],String[] ……,Dictory字典等等。但是这些列表、集合和数组的线程都不是安全的,不能接受并发请求。例如:


C#
namespace Spider{
    class Program
    {

        private static List<Product> _Products { get; set; }        static void Main(string[] args)
        {

            _Products = new List<Product>();
            Task t1 = Task.Factory.StartNew(() =>
            {
                AddProducts();
            });
            Task t2 = Task.Factory.StartNew(() =>
            {
                AddProducts();
            });
            Task t3 = Task.Factory.StartNew(() =>
            {
                AddProducts();
            });

            Task.WaitAll(t1, t2, t3);//同步执行
            Console.WriteLine(_Products.Count);
            Console.ReadLine();
        }        static void AddProducts()
        {
            Parallel.For(0, 1000, (i) =>
            {
                Product product = new Product();
                product.Name = "name" + i;
                product.Category = "Category" + i;
                product.SellPrice = i;
                _Products.Add(product);
            });

        }
    }    class Product
    {
        public string Name { get; set; }        public string Category { get; set; }        public int SellPrice { get; set; }
    }}


上图理论上是会显示3000行数据,但是实际上显示了2934个由于是list集合并不能保证线程安全,所以导致数据丢失,无法保证数据的一致性。这个时候我们常用的解决方法就是加锁(lock)lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。


C#
static void Main(string[] args)
        {

            _Products = new List<Product>();
            Stopwatch swTask = new Stopwatch();//用于统计时间消耗的
            swTask.Start();
            Task t1 = Task.Factory.StartNew(() =>
            {
                AddProducts();
            });            Task t2 = Task.Factory.StartNew(() =>
            {
                AddProducts();
            });            Task t3 = Task.Factory.StartNew(() =>
            {
                AddProducts();
            });            Task.WaitAll(t1, t2, t3);//同步执行            swTask.Stop();            Console.WriteLine("List<Product> 当前数据量为:" + _Products.Count);            Console.WriteLine("List<Product> 执行时间为:" + swTask.ElapsedMilliseconds);            Console.ReadLine();
        }        static void AddProducts()
        {            Parallel.For(0, 1000000, (i) =>
            {
                lock (_Products)
                {

                    Product product = new Product();
                    product.Name = "name" + i;
                    product.Category = "Category" + i;
                    product.SellPrice = i;
                    _Products.Add(product);
                }                 //lock 是Monitor的语法糖                //Monitor.Enter(_Products);                //Product product = new Product();                //product.Name = "name" + i;                //product.Category = "Category" + i;                //product.SellPrice = i;                //_Products.Add(product);                //Monitor.Exit(_Products);
            });

        }
C#
List<Product> 当前数据量为:3000000List<Product> 执行时间为:4638


这个时候就显示3000

但是锁的引入,带来了一定的开销和性能的损耗,并降低了程序的扩展性,而且还会有死锁的发生(虽说概率不大,但也不能不防啊),因此:使用LOCK进行并发编程显然不太适用。

还好,微软一直在更新自己的东西:

.NET Framework 4提供了新的线程安全和扩展的并发集合,它们能够解决潜在的死锁问题和竞争条件问题,因此在很多复杂的情形下它们能够使得并行代码更容易编写,这些集合尽可能减少使用锁的次数,从而使得在大部分情形下能够优化为最佳性能,不会产生不必要的同步开销。

需要注意的是:在串行代码中使用并发集合是没有意义的,因为它们会增加无谓的开销。

在.NET Framework4.0以后的版本中提供了命名空间:System.Collections.Concurrent 来解决线程安全问题,通过这个命名空间,能访问以下为并发做好了准备的集合。

1.BlockingCollection 与经典的阻塞队列数据结构类似,能够适用于多个任务添加和删除数据,提供阻塞和限界能力。

2.ConcurrentBag 提供对象的线程安全的无序集合

3.ConcurrentDictionary 提供可有多个线程同时访问的键值对的线程安全集合

4.ConcurrentQueue 提供线程安全的先进先出集合

5.ConcurrentStack 提供线程安全的后进先出集合

这些集合通过使用比较并交换和内存屏障等技术,避免使用典型的互斥重量级的锁,从而保证线程安全和性能。

C#
static void Main(string[] args)
        {

            _Products = new ConcurrentQueue<Product>();
            Stopwatch swTask = new Stopwatch();//用于统计时间消耗的
            swTask.Start();
            Task t1 = Task.Factory.StartNew(() =>
            {
                AddProducts();
            });            Task t2 = Task.Factory.StartNew(() =>
            {
                AddProducts();
            });            Task t3 = Task.Factory.StartNew(() =>
            {
                AddProducts();
            });            Task.WaitAll(t1, t2, t3);//同步执行            swTask.Stop();            Console.WriteLine("List<Product> 当前数据量为:" + _Products.Count);            Console.WriteLine("List<Product> 执行时间为:" + swTask.ElapsedMilliseconds);            Console.ReadLine();
        }        static void AddProducts()
        {            Parallel.For(0, 1000000, (i) =>
            {

                    Product product = new Product();
                    product.Name = "name" + i;
                    product.Category = "Category" + i;
                    product.SellPrice = i;
                    _Products.Enqueue(product);

            });

        }
    }

List 当前数据量为:3000000 
List 执行时间为:2911 
“` 
得出结果


#转载请注明出处 www.skcircle.com 《少有人走的路》勇哥的工业自动化技术网站。

扫描二维码推送至手机访问。

版权声明:本文由7点博客发布,如需转载请注明出处。

本文链接:http://6dot.cn/?id=138

标签: .NET.NET框架
分享给朋友:

“C# .net 集合-并发处理(List集合换成ConcurrentQueue、ConcurrentDictionary )” 的相关文章

windows下c#程序提高实时性

windows下c#程序提高实时性

引言:我们手里的运控软件对实时性有了新要求。因为同设备上运行的其它视觉软件对cpu时间有变态的占用,压缩了运控软件的cpu占用时间。我们知道如果视觉软件卡一下,最多是处理时间长一点,但是运控软件卡一下,那就意味着撞机的问题,这个要严重得多。这个问题会持续把研究结果更新到本贴子。(一)提升线程和进程的...

C# 控件闪烁问题的解决

C# 控件闪烁问题的解决

说一下解决C#下控件闪烁的几个问题,如下:  listview和datagridview显示数据闪烁 自定义控件的显示闪烁listbox滚动条拖动闪烁面板中控件过多的闪烁propertyGrid点击和修改项目缓慢的问题richtextbox控件的刷新显示问题此类问题对于界面复杂规...

C#的propertygrid控件,选择和修改项目时很慢

C#的propertygrid控件,选择和修改项目时很慢

C#的propertygrid控件是很强。可以实现类似Vitual Studio属性面板那样的效果。但是。。。。我们一直痛苦它在选择和修改项目的时候很慢。我的用法是使用控件的SelectObject来绑定数据。C# PgridMotionSpeed.SelectedObject ...

C# Modelbus crc16计算校验和程序

C# Modelbus crc16计算校验和程序

我们手里一个无刷电机,采用485的modelbus crc16协议来控制。因此需要一个计算校验和的工具。源码:C#using System;using System.Collections.Generic;using System.ComponentModel;usin...

C# tableLayoutPanel动态加载控件闪烁的解决方案

C# tableLayoutPanel动态加载控件闪烁的解决方案

WinForm加载多个自定义控件时,会出现很严重的闪烁问题,很卡,一块一块的加载(像打开网页时,网络很卡的那种感觉)简直没法忍受。在网上搜索了好久,网上大部分的方法是一下4种,但是都不能有效的解决问题。  1.将DoubleBuffered 设置 true,用双缓存处理Form界面内容加载,可以提高...

计算代码执行时间,可以精确到十亿分之一秒

计算代码执行时间,可以精确到十亿分之一秒

注:.Net的Stopwatch类可以精确到1/10000毫秒, 有没有更精确的计时吗?见下面的代码。暂时没试过效果,大家可以试下。计算某个代码片段的执行时间,精确到CPU执行一条指令所用的时间(十亿分之一秒),可用于精确计算某个算法的执行时间。 代码:C#using Syste...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。