• .Net(C#)Parallel"循环"的解释以及与循环的比较


    Parallel 类提供对并行循环和区域的支持。

    许多个人计算机和工作站都有两个或四个内核(即 CPU),使多个线程能够同时执行。 在不久的将来,计算机预期会有更多的内核。 为了利用当今和未来的硬件,您可以对代码进行并行化,以将工作分摊在多个处理器上。 过去,并行化需要线程和锁的低级操作。 Visual Studio 2010 和 .NET Framework 4 提供了新的运行时、新的类库类型以及新的诊断工具,从而增强了对并行编程的支持。 这些功能简化了并行开发,使您能够通过固有方法编写高效、细化且可伸缩的并行代码,而不必直接处理线程或线程池。 下图从较高层面上概述了 .NET Framework 4 中的并行编程体系结构。

    IC387462

    上面是MSDN对于并行任务的解释,简而言之就是同时执行多个任务,带来效率上的提高,但是同时带来CPU占用;

    1.简单Parallel.For/Parallel.ForEach循环

    using System;
    using System.Diagnostics;
    using System.Threading;
    using System.Threading.Tasks;
     
    namespace ConsoleApplication17
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    NormalFor();
                    ParallelFor();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(string.Format("Exception Message:{0}", ex.Message.Trim()));
                }
                finally
                {
                    Console.ReadLine();
                }
            }
            static int _forCount = 100;
            static void NormalFor()
            {
                Stopwatch _watch = new Stopwatch();
                _watch.Start();
                for (int i = 0; i < _forCount; i++)
                {
                    DoSomeWork(i);
                }
                _watch.Stop();
                Console.WriteLine(string.Format("Normal For Cost Time:{0}", _watch.ElapsedMilliseconds));
            }
            static void ParallelFor()
            {
                Stopwatch _watch = new Stopwatch();
                _watch.Start();
                //写法一
                Parallel.For(0, _forCount, i =>
                {
                    DoSomeWork(i);
                });
                _watch.Stop();
                Console.WriteLine(string.Format("Parallel For Cost Time:{0}", _watch.ElapsedMilliseconds));
                /*
                Parallel.For(0, _forCount, DoSomeWork);//写法二
                Parallel.For(0, _forCount, (int i) => { DoSomeWork(i); });//写法三
                */
            }
            static void DoSomeWork(int i)
            {
                if (i < 0)
                    throw new ArgumentException("i");
                Thread.Sleep(100);
            }
        }
    }

    代码效果

    image

    2.停止或中断 Parallel.For 循环

    using System;
    using System.Diagnostics;
    using System.Threading;
    using System.Threading.Tasks;
     
    namespace ConsoleApplication17
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    BreakParallelFor();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(string.Format("Exception Message:{0}", ex.Message.Trim()));
                }
                finally
                {
                    Console.ReadLine();
                }
            }
            static int _forCount = 100;
            static void BreakParallelFor()
            {
                Parallel.For(0, _forCount, (i, status) =>
                {
                    if (i == 22)
                    {
                        Console.WriteLine("Parallel For Break....");
                        status.Break();
                    }
                    Console.WriteLine(string.Format("output :{0}", i));
                    Thread.Sleep(100);
                });
            }
        }
    }

    代码效果

    image

    看看MSDN关于此的解释:

    在 ParallelFor() 或 [Overload:System.Threading.Tasks.Parallel.Parallel.ForEach`1] 循环中,不能使用与顺序循环中相同的 break 或 Exit 语句,这是因为这些语言构造对于循环是有效的,而并行“循环”实际上是方法,不是循环。 相反,可以使用 Stop 或 Break 方法。 Parallel.For的一些重载接受 Action<int, ParallelLoopState>(在 Visual Basic 中为 Action(Of Integer, ParallelLoopState))作为输入参数。 ParallelLoopState 对象由运行时在后台创建,您可以在 lambda 表达式中为它指定您喜欢的任何名称。

    在调用 Stop 或 Break 后,循环中的其他线程可能会继续运行一段时间(这不受应用程序开发人员的控制),理解这一点很重要。 可以使用 ParallelLoopState.IsStopped 属性检查是否已在另一个线程上停止该循环。

    理解黄色标注地方很重要;

    3.具有线程局部变量的 Parallel.ForEach Parallel.For 循环(代码很乱未调!)

    1. using System;  
    2. using System.Linq;  
    3. using System.Threading;  
    4. using System.Threading.Tasks;  
    5. namespace ConsoleApplication17{      
    6. class Program    {          
    7.      static void Main(string[] args)           {              
    8.          try              
    9.          {                //例子参考自MSDN:http://msdn.microsoft.com/zh-cn/library/dd460703%28v=vs.100%29.aspx                  
    10.              int[] _nums = Enumerable.Range(0, 10).ToArray();                  
    11.              long _fortotal = 0, _foreahtotal = 0;                  
    12.              Parallel.For<long>(0, _nums.Length,                    () => 0,//每次遍历开始时候初始化变量 类似于 int _subSum=0;                     
    13.          (i, loopStatus, eachLoopTotal) =>//i:循环的索引;loopstatus:并行遍历状态;eachLoopTotal:每次遍历累加小计值                     
    14.                  {                          
    15.                      eachLoopTotal += _nums[i];                          
    16.                      return eachLoopTotal;                      
    17.                      },                      
    18.                      (eachLoopTotal) =>//遍历结束时候,将上面每次累加小计数值传递过来,进行总的累加                     
    19. {                        Interlocked.Add(ref _fortotal, eachLoopTotal);                      
    20. });                /*                 
    21. localInit                     
    22. 类型:System.Func<TLocal>                     
    23. 用于返回每个线程的本地数据的初始状态的函数委托。                
    24.  body                     
    25.  类型:System.Func<Int64, ParallelLoopState, TLocal, TLocal>                     
    26.  将为每个迭代调用一次的委托。                
    27. localFinally                     
    28.   类型:System.Action<TLocal>                     
    29.   用于对每个线程的本地状态执行一个最终操作的委托。                 
    30. */                  
    31.                    
    32.                  Parallel.ForEach<int, long>(_nums,                        
    33.                          () => 0,                        
    34.                          (i, loopStatus, eachLoopTotal) =>                        
    35.                          {                            
    36.                              eachLoopTotal += _nums[i];                            
    37.                              return eachLoopTotal;                        
    38.                              },                        
    39.                              (eachLoopTotal) =>                        
    40.                              {                            
    41.                                  Interlocked.Add(ref _foreahtotal, eachLoopTotal);                        
    42.                                  });                  
    43.                  Console.WriteLine("The Parallel.For is {0}", _fortotal);                  
    44.                  Console.WriteLine("The Parallel.ForEach is {0}", _foreahtotal);              
    45.                  }            catch (Exception ex)              
    46.                  {                  
    47.                      Console.WriteLine(string.Format("Exception Message:{0}", ex.Message.Trim()));              
    48.                      }              
    49.                  finally              
    50.                  {                  
    51.                      Console.ReadLine();              
    52.                      }          
    53.                  }      
    54.          }}  
    55.                  }  
    56.              }  
    57.          }  

     

    代码效果

    image

    4.取消 Parallel.For/ForEach Loop

    using System;
    using System.Threading;
    using System.Threading.Tasks;
     
    namespace ConsoleApplication17
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    /*
                     CancellationToken 获取或设置与此 ParallelOptions 实例关联的 CancellationToken。 
                     MaxDegreeOfParallelism 获取或设置此 ParallelOptions 实例所允许的最大并行度。 
                     TaskScheduler 获取或设置与此 ParallelOptions 实例关联的 TaskScheduler。 将此属性设置为 null,以指示应使用当前计划程序。
                     MaxDegreeOfParallelism MaxDegreeOfParallelism设置为2,表示最多可以有2个并行量(可以理解成并行线程数目),如果设置为为 -1,表示对于应该使用的并行量没有上限设置。如果将其设置为1,则效果和单线程一样.
                     */
                    CancellationTokenSource _cancel = new CancellationTokenSource();
                    ParallelOptions _po = new ParallelOptions();
                    _po.CancellationToken = _cancel.Token;
                    _po.MaxDegreeOfParallelism = Environment.ProcessorCount;
     
                    Parallel.For(0, 100, _po, i =>
                        {
                            if (i == 22)
                                _cancel.Cancel();
                            Console.WriteLine(string.Format("output {0}", i));
                        });
                }
                catch (OperationCanceledException e)
                {
                    Console.WriteLine(e.Message);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(string.Format("Exception Message:{0}", ex.Message.Trim()));
                }
                finally
                {
                    Console.ReadLine();
                }
            }
        }
    }

    代码效果

    image

  • 相关阅读:
    OpenStack 发行版本
    刷新linux硬盘存储接口
    LVM实践
    LVM man帮助
    ansible --help 文档
    nmcli connection modify eth1 ipv4.addr "192.168.31.23" ipv4.method manual
    自己动手使用, MetaWeblog 发布博客(cnblogs)
    测试图片上传 on Markdown editor
    大批量更新数据mysql批量更新的四种方法
    PHP print_r 转换/还原为数组
  • 原文地址:https://www.cnblogs.com/liujiangping/p/5012576.html
Copyright © 2020-2023  润新知