zoukankan      html  css  js  c++  java
  • C#中的并发编程知识二

    对于并行任务,与其相关紧密的就是对一些共享资源,数据结构的并行访问。经常要做的就是对一些队列进行加锁-解锁,然后执行类似插入,删除等等互斥操作。 .NetFramework 4.0 中提供了一些封装好的支持并行操作数据容器,可以减少并行编程的复杂程度。

    基本信息

    .NetFramework中并行集合的名字空间: System.Collections.Concurrent

    并发容器

    • ConcurrentQueue
    • ConcurrentStack
    • ConcurrentDictionary
    • ConcurrentBag:一个无序的数据结构集,当不需要考虑顺序时非常有用。
    • BlockingCollection与经典的阻塞队列数据结构类似

    这些集合在某种程度上使用了无锁技术(CAS Compare-and-Swap和内存屏障Memory Barrier),与加互斥锁相比获得了性能的提升。但在串行程序中,最好不用这些集合,它们必然会影响性能。

    ConcurrentQueue

    其完全无锁,但当CAS面临资源竞争失败时可能会陷入自旋并重试操作。

    • Enqueue:在队尾插入元素
    • TryDequeue:尝试删除队头元素,并通过out参数返回
    • TryPeek:尝试将对头元素通过out参数返回,但不删除该元素。
    
            class Program
              {
                  internal static ConcurrentQueue<int> _TestQueue;
            
                  class ThreadWork1  // producer  
                  {
                      public void run()
                      {
                          System.Console.WriteLine("ThreadWork1 run { ");
                          for (int i = 0; i < 30; i++)
                          {
                              System.Console.WriteLine("ThreadWork1 producer: " + i);
                              _TestQueue.Enqueue(i);
                          }
                          System.Console.WriteLine("ThreadWork1 run } ");
                      }
                  }
            
                  class ThreadWork2  // consumer  
                  {
            
                      public void run()
                      {     
                          int i=0;       
                          bool IsDequeuue = false;
                          System.Console.WriteLine("ThreadWork2 run { ");
                          for (;; i++)
                          {
                              IsDequeuue = _TestQueue.TryDequeue(out i);
                              if (IsDequeuue)
                                  System.Console.WriteLine("ThreadWork2 consumer: " + i * i + "   =====");
            
                              if (i == 29)
                                  break;
                          }
                          System.Console.WriteLine("ThreadWork2 run } ");
                      }
                  }
            
                  static void StartT1()
                  {
                      ThreadWork1 work1 = new ThreadWork1();
                      work1.run();
                  }
            
                  static void StartT2()
                  {
                      ThreadWork2 work2 = new ThreadWork2();
                      work2.run();
                  }  
            
            
                  public static void Main()
                  {
                      Task t1 = new Task(() => StartT1());
                      Task t2 = new Task(() => StartT2());
                      _TestQueue = new ConcurrentQueue<int>();
                      Console.WriteLine("Main {");
            
                      Console.WriteLine("Main t1 t2 started {");
                      t1.Start();
                      t2.Start();
                      Console.WriteLine("Main t1 t2 started }");
            
                      Console.WriteLine("Main wait t1 t2 end {");
                      Task.WaitAll(t1, t2);
                      Console.WriteLine("Main wait t1 t2 end }");
            
                      Console.WriteLine("Main }");  
            
                      Console.ReadKey();
                  }
              }
                 
    imgs/bb-1.jpg imgs/bb-2.jpg

    ConcurrentStack

    其完全无锁,但当CAS面临资源竞争失败时可能会陷入自旋并重试操作。

    • Push:向栈顶插入元素
    • TryPop:从栈顶弹出元素,并且通过out 参数返回
    • TryPeek:返回栈顶元素,但不弹出

    ConcurrentBag

    一个无序的集合,程序可以向其中插入元素,或删除元素。

    在同一个线程中向集合插入,删除元素的效率很高。

    • Add:向集合中插入元素
    • TryTake:从集合中取出元素并删除
    • TryPeek:从集合中取出元素,但不删除该元素。

    BlockingCollection

    一个支持界限和阻塞的容器

    • Add:向容器中插入元素
    • TryTake:从容器中取出元素并删除
    • TryPeek:从容器中取出元素,但不删除。
    • CompleteAdding:告诉容器,添加元素完成。此时如果还想继续添加会发生异常。
    • IsCompleted:告诉消费线程,生产者线程还在继续运行中,任务还未完成。

    要点一:消费者线程完全使用 while (!_TestBCollection.IsCompleted) 作为退出运行的判断条件

    要点二:当BlockingCollection对象设置为CompleteAdding(.CompleteAdding()),但当继续向其中插入元素时,系统抛出异常,提示无法再继续插入。

    
            class Program
            {
                internal static BlockingCollection<int> _TestBCollection;
            
                class ThreadWork1  // producer  
                {
                    public ThreadWork1()
                    { }
            
                    public void run()
                    {
                        System.Console.WriteLine("ThreadWork1 run { ");
                        for (int i = 0; i < 100; i++)
                        {
                            System.Console.WriteLine("ThreadWork1 producer: " + i);
                            _TestBCollection.Add(i);
                            //if (i == 50)  
                            //    _TestBCollection.CompleteAdding();  
                        }
                        _TestBCollection.CompleteAdding();
            
                        System.Console.WriteLine("ThreadWork1 run } ");
                    }
                }
            
                class ThreadWork2  // consumer  
                {
                    public ThreadWork2()
                    { }
            
                    public void run()
                    {
                        int i = 0;
                        int nCnt = 0;
                        bool IsDequeuue = false;
                        System.Console.WriteLine("ThreadWork2 run { ");
                        while (!_TestBCollection.IsCompleted)
                        {
                            IsDequeuue = _TestBCollection.TryTake(out i);
                            if (IsDequeuue)
                            {
                                System.Console.WriteLine("ThreadWork2 consumer: " + i * i + "   =====" + i);
                                nCnt++;
                            }
                        }
                        System.Console.WriteLine("ThreadWork2 run } ");
                    }
                }
            
                static void StartT1()
                {
                    ThreadWork1 work1 = new ThreadWork1();
                    work1.run();
                }
            
                static void StartT2()
                {
                    ThreadWork2 work2 = new ThreadWork2();
                    work2.run();
                }
                static void Main(string[] args)
                {
                    Task t1 = new Task(() => StartT1());
                    Task t2 = new Task(() => StartT2());
            
                    _TestBCollection = new BlockingCollection<int>();
            
                    Console.WriteLine("Sample 4-4 Main {");
            
                    Console.WriteLine("Main t1 t2 started {");
                    t1.Start();
                    t2.Start();
                    Console.WriteLine("Main t1 t2 started }");
            
                    Console.WriteLine("Main wait t1 t2 end {");
                    Task.WaitAll(t1, t2);
                    Console.WriteLine("Main wait t1 t2 end }");
            
                    Console.WriteLine("Sample 4-4 Main }");
            
                    Console.ReadKey();
                }
            }
                 
    imgs/bb-3.jpg

    ConcurrentDictionary

    对于读操作是完全无锁的,当很多线程要修改数据时,它会使用细粒度的锁。

    • AddOrUpdate:如果键不存在,方法会在容器中添加新的键和值,如果存在,则更新现有的键和值。
    • GetOrAdd:如果键不存在,方法会向容器中添加新的键和值,如果存在则返回现有的值,并不添加新值。
    • TryAdd:尝试在容器中添加新的键和值。
    • TryGetValue:尝试根据指定的键获得值。
    • TryRemove:尝试删除指定的键。
    • TryUpdate:有条件的更新当前键所对应的值。
    • GetEnumerator:返回一个能够遍历整个容器的枚举器。
    
            class Program
            {  
                internal static ConcurrentDictionary<int, int> _TestDictionary;  
      
                class ThreadWork1  // producer  
                {  
                    public ThreadWork1()  
                    { }  
      
                    public void run()  
                    {  
                        System.Console.WriteLine("ThreadWork1 run { ");  
                        for (int i = 0; i < 100; i++)  
                        {  
                            System.Console.WriteLine("ThreadWork1 producer: " + i);  
                            _TestDictionary.TryAdd(i, i);  
                        }  
      
                        System.Console.WriteLine("ThreadWork1 run } ");  
                    }  
                }  
      
                class ThreadWork2  // consumer  
                {  
                    public ThreadWork2()  
                    { }  
      
                    public void run()  
                    {  
                        int i = 0, nCnt = 0;  
                        int nValue = 0;  
                        bool IsOk = false;  
                        System.Console.WriteLine("ThreadWork2 run { ");  
                        while (nCnt < 100)  
                        {  
                            IsOk = _TestDictionary.TryGetValue(i, out nValue);  
                            if (IsOk)  
                            {  
                                System.Console.WriteLine("ThreadWork2 consumer: " + i * i + "   =====" + i);  
                                nValue = nValue * nValue;  
                                _TestDictionary.AddOrUpdate(i, nValue, (key, value) => { return value = nValue; });  
                                nCnt++;  
                                i++;  
                            }  
                        }  
                        System.Console.WriteLine("ThreadWork2 run } ");  
                    }  
                }  
      
                static void StartT1()  
                {  
                    ThreadWork1 work1 = new ThreadWork1();  
                    work1.run();  
                }  
      
                static void StartT2()  
                {  
                    ThreadWork2 work2 = new ThreadWork2();  
                    work2.run();  
                }  
                static void Main(string[] args)  
                {  
                    Task t1 = new Task(() => StartT1());  
                    Task t2 = new Task(() => StartT2());  
                    bool bIsNext = true;  
                    int  nValue = 0;  
      
                    _TestDictionary = new ConcurrentDictionary<int, int>();  
      
                    Console.WriteLine("Sample 4-5 Main {");  
      
                    Console.WriteLine("Main t1 t2 started {");  
                    t1.Start();  
                    t2.Start();  
                    Console.WriteLine("Main t1 t2 started }");  
      
                    Console.WriteLine("Main wait t1 t2 end {");  
                    Task.WaitAll(t1, t2);  
                    Console.WriteLine("Main wait t1 t2 end }");
    
                    #region 其他
                    foreach (var pair in _TestDictionary)
                    {
                        Console.WriteLine(pair.Key + " : " + pair.Value);
                    }
    
                    System.Collections.Generic.IEnumerator<System.Collections.Generic.KeyValuePair<int, int>>
                        enumer = _TestDictionary.GetEnumerator();
    
                    while (bIsNext)
                    {
                        bIsNext = enumer.MoveNext();
                        Console.WriteLine("Key: " + enumer.Current.Key +
                                          "  Value: " + enumer.Current.Value);
    
                        _TestDictionary.TryRemove(enumer.Current.Key, out nValue);
                    }
    
                    #endregion
    
                    Console.WriteLine("
    
    Dictionary Count: " + _TestDictionary.Count);  
      
                    Console.WriteLine("Sample 4-5 Main }");  
      
                    Console.ReadKey();  
                }  
            }  
                 
    imgs/bb-4.jpg
  • 相关阅读:
    程序员小抄大全
    赢在中国“80后30个忠告”
    Eclipse下python插件(pydev)的安装
    PDF加密文件的解密和打印
    中美欧联手打击僵尸网络 深化安全合作 狼人:
    入侵奥巴马帐号法国黑客自称是一个好黑客 狼人:
    Firefox 3.6.3版率先修复黑客大赛所曝漏洞 狼人:
    2009年全球安全SaaS市场收入比2008年增长70% 狼人:
    微软等厂商高管谈安全云面临的挑战 狼人:
    报告称Windows7不安全 管理员权限是罪魁祸首 狼人:
  • 原文地址:https://www.cnblogs.com/wwkk/p/6599580.html
Copyright © 2011-2022 走看看