• c# 并行运算


    c# 并行运算

    1. Parallel.INVOKE() 看实例:

        private static Stopwatch watch = new Stopwatch();
    
            private static void Run1()
            {
                Thread.Sleep(2000);
                Console.WriteLine("Task 1 takes 2 sec");
            }
            private static void Run2()
            {
                Thread.Sleep(3000);
                Console.WriteLine("Task 2 takes 3 sec");
            }
    
            static void Main(string[] args)
            {
                watch.Start();
                Parallel.Invoke(Run1,Run2);
                watch.Stop();
                Console.WriteLine("Parallel run "+watch.ElapsedMilliseconds +" ms");
           
    
    
                watch.Restart();
                Run1();
                Run2();
                watch.Stop();
                Console.WriteLine("Normal run "+watch.ElapsedMilliseconds+" ms");
    
                Console.ReadLine();

    看结果:

     

     2.Parallel.For

     看实例:

      watch.Start();
                for (int i = 0; i < 10000; i++)
                {
                    for (int j = 0; j < 5000; j++)
                    {
                        int sum = 0;
                        sum++;
                    }
                }
                watch.Stop();
                Console.WriteLine("Normal run " + watch.ElapsedMilliseconds + "ms");
    
                watch.Restart();
                watch.Start();
                Parallel.For(0, 1000, item =>
                  {
                      for (int j = 0; j < 5000; j++)
                      {
                          int sum = 0;
                          sum += item;
                      }
    
                  });
    
                watch.Stop();
                Console.WriteLine("ParalleFor run " + watch.ElapsedMilliseconds + "ms");
    
                Console.ReadLine();

    看结果:

     

    是不是Parallel.For在任何时候都比for要快呢?答案当然是“不是”,要不然微软还留着for干嘛?

    看实例:

       var obj = new object();
                long num = 0;
                ConcurrentBag<long> bag = new ConcurrentBag<long>();
                watch.Start();
                for (int i = 0; i < 10000; i++)
                {
                    for (int j = 0; j < 5000; j++)
                    {
                        //    int sum = 0;
                        //    sum++;
                        num++;
                    }
                }
    
                watch.Stop();
                Console.WriteLine("Normal run "+watch.ElapsedMilliseconds+ "Ms");
    
                watch.Restart();
    
                Parallel.For(0, 1000, item =>
                {
                    for (int j = 0; j < 5000; j++)
                    {
                        //int sum = 0;
                        //sum += item;
                        lock (obj)
                        {
                            num++; //全局变量,就要考虑到线程安全了
                            //这主要是由于并行同时访问全局变量,会出现资源争夺,大多数时间消耗在了资源等待上面。
                        }
                    }
    
                });
    
                watch.Stop();
                Console.WriteLine("ParalleFor run " + watch.ElapsedMilliseconds + "ms");
    
                Console.ReadLine();

    结果:(结果不是稳定的,你懂得~)

    再看代码:

      Parallel.For(0, 100, i =>
                  {
                      Console.Write( i +"	");
                  });
               
                Console.ReadLine();

    再看结果:

     傻孩子,这样你懂了吧~

     3.Parallel.Foreach

      

    //Environment.ProcessorCount能够获取到当前的硬件线程数,所以这里也就开了2个区。
                Console.WriteLine(Environment.ProcessorCount);
                Console.ReadLine();
                //继续我的并发编程;
    
                //可以将数据进行分区,每一个小区内实现串行计算;分区采用Create实现;
    
                for (int j = 1; j < 4; j++)
                {
                    Console.WriteLine("
    第{0}次比较", j);
                    ConcurrentBag<int> bag = new ConcurrentBag<int>();
                    watch.Start();
    
                    for (int i = 0; i < 300000; i++)
                    {
                        bag.Add(i);
                    }
    
                    Console.WriteLine("串行计算:集合有{0},总共耗时:{1}",bag.Count,watch.ElapsedMilliseconds);
    
                    GC.Collect();
                    bag = new ConcurrentBag<int>();
                    watch.Restart();
                    Parallel.ForEach(Partitioner.Create(0, 300000), i =>
                     {
                         for (int m = i.Item1; m < i.Item2; m++)
                         {
                             bag.Add(m);
                         }
                     });
                    Console.WriteLine("并行计算:集合有:{0},总共耗时:{1}", bag.Count, watch.ElapsedMilliseconds);
    
                    GC.Collect();
                    watch.Stop();
                }           
    
                Console.ReadLine();

     结果:

     

    4.parallel 中途退出循环

    Break: 当然这个是通知并行计算尽快的退出循环,比如并行计算正在迭代100,那么break后程序还会迭代所有小于100的。

    Stop:这个就不一样了,比如正在迭代100突然遇到stop,那它啥也不管了,直接退出。

     

        ConcurrentBag<long> bag = new ConcurrentBag<long>();
                watch.Start();
    
                Parallel.For(0,1000, (i, state) =>
                 {
                     if (bag.Count == 300)
                     {
                         state.Break();
                         //当数量达到300个时,会立刻停止;可以看到结果"Bag count is 300",如果用break,可能结果是300多个或者300个,大家可以测试一下。
                         return;
                     }
                     bag.Add(i);
    
                 });
                watch.Stop();
                Console.WriteLine("Bag count is "+bag.Count+"  times is "+watch.ElapsedMilliseconds);

     异常处理

    由于Task的Start方法是异步启动的,所以我们需要额外的技术来完成异常处理

     try  
        {  
            var parallelExceptions = new ConcurrentQueue<Exception>();  
            Parallel.For(0, 1, (i) => 
            {  
                try  
                {  
                    throw new InvalidOperationException("并行任务中出现的异常");  
                }  
                catch (Exception e)  
                {  
                    parallelExceptions.Enqueue(e);  
                }  
                if (parallelExceptions.Count > 0)  
                    throw new AggregateException(parallelExceptions);  
            });  
        }  
        catch (AggregateException err)  
        {  
            foreach (Exception item in err.InnerExceptions)  
            {  
                Console.WriteLine("异常类型:{0}{1}来自:  
                    {2}{3}异常内容:{4}", item.InnerException.GetType(),  
                    Environment.NewLine, item.InnerException.Source,  
                    Environment.NewLine, item.InnerException.Message);  
            }  
        }  
        Console.WriteLine("主线程马上结束");  
        Console.ReadKey();  
    static void Main(string[] args)
            {
                try
                {
                    Parallel.Invoke(Run1, Run2);
                    //这个捕获
                    //在不同的模式下,会有不同结果地呀;
                    //debug 模式下,会停止的
                    //realse 模式下就可以获取异常;
                }
                catch (AggregateException ex)
                {
                    foreach (var single in ex.InnerExceptions)
                    {
                        Console.WriteLine(single.Message);
                    }
                }
    
                Console.Read();
            }
    
            static void Run1()
            {
                Thread.Sleep(3000);
                throw new Exception("我是任务1抛出的异常");
            }
    
            static void Run2()
            {
                Thread.Sleep(5000);
    
                throw new Exception("我是任务2抛出的异常");
            }

    实例二

     try
                {
                    go1();  //这样的异常只能捕获其中一个地呀;
                            
                    go2();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                watch.Stop();
                Console.WriteLine("Normal run :" + watch.ElapsedMilliseconds);
                //尼玛的,这样的异常,居然捕获不到的地呀

     默认的情况下,底层机制会尽可能多的使用硬件线程,然而我们使用手动指定的好处是我们可以在2,4,8个硬件线程的情况下来进行测量加速比。 

    class Program
        {
            static void Main(string[] args)
            {
                var bag = new ConcurrentBag<int>();
    
                ParallelOptions options = new ParallelOptions();
    
                //指定使用的硬件线程数为1
                options.MaxDegreeOfParallelism = 1;
    
                Parallel.For(0, 300000, options, i =>
                {
                    bag.Add(i);
                });
    
                Console.WriteLine("并行计算:集合有:{0}", bag.Count);
    
            }
        }
  • 相关阅读:
    【Spark学习笔记】第一章 Windows10(64位)主机上搭建基于IntelliJ IDEA的spark+scala开发环境
    【Oracle数据库相关】Oracle数据库在CentOS6.5环境下的安装以及相关操作
    【SNMP】Linux系统下安装net-snmp
    【SNMP】SNMP概述
    【转】 memwatch使用说明书
    [转]GCC参数详解
    【Linux C中文函数手册】 字符串转换函数
    【Linux C中文函数手册】文件内容控制函数
    【Linux C中文函数手册】之 目录操作函数
    [心智历练]---高效、静心、持续
  • 原文地址:https://www.cnblogs.com/mc67/p/5912711.html
Copyright © 2020-2023  润新知