[C#]『Parallel.For』『Parallel.ForEach』任务并行库使用小计

[C#]『Parallel.For』『Parallel.ForEach』任务并行库使用小计Parallel类提供对并行循环和区域的支持。许多个人计算机和工作站都有两个或四个内核(即CPU),使多个线程能够同时执行。在不久的将来,计算机预期会有更多的内核。为了利用当今和未来的硬件,您可以对代码进行并行化,以将工作分摊在多个处理器上。过去,并行化需要线程和锁的低级操作。VisualStudio2010和.NETFramework4提供了新的运行时、新的



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 循环(代码很乱未调!)

using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication17{    
class Program    {        
     static void Main(string[] args)           {            
    	 try            
    	 {                //例子参考自MSDN:http://msdn.microsoft.com/zh-cn/library/dd460703%28v=vs.100%29.aspx                
    		 int[] _nums = Enumerable.Range(0, 10).ToArray();                
    		 long _fortotal = 0, _foreahtotal = 0;                
    		 Parallel.For<long>(0, _nums.Length,                    () => 0,//每次遍历开始时候初始化变量 类似于 int _subSum=0;                   
		 (i, loopStatus, eachLoopTotal) =>//i:循环的索引;loopstatus:并行遍历状态;eachLoopTotal:每次遍历累加小计值                   
	    		 {                        
	    			 eachLoopTotal += _nums[i];                        
	    			 return eachLoopTotal;                    
	    			 },                    
	    			 (eachLoopTotal) =>//遍历结束时候,将上面每次累加小计数值传递过来,进行总的累加                   
{                        Interlocked.Add(ref _fortotal, eachLoopTotal);                    
});                /*                
localInit                    
类型:System.Func<TLocal>                    
用于返回每个线程的本地数据的初始状态的函数委托。               
 body                    
 类型:System.Func<Int64, ParallelLoopState, TLocal, TLocal>                    
 将为每个迭代调用一次的委托。               
localFinally                    
  类型:System.Action<TLocal>                    
  用于对每个线程的本地状态执行一个最终操作的委托。                
*/                
	    		 
	    		 Parallel.ForEach<int, long>(_nums,                      
	    				 () => 0,                      
	    				 (i, loopStatus, eachLoopTotal) =>                      
	    				 {                          
	    					 eachLoopTotal += _nums[i];                          
	    					 return eachLoopTotal;                      
	    					 },                      
	    					 (eachLoopTotal) =>                      
	    					 {                          
	    						 Interlocked.Add(ref _foreahtotal, eachLoopTotal);                      
	    						 });                
	    		 Console.WriteLine("The Parallel.For is {0}", _fortotal);                
	    		 Console.WriteLine("The Parallel.ForEach is {0}", _foreahtotal);            
	    		 }            catch (Exception ex)            
	    		 {                
	    			 Console.WriteLine(string.Format("Exception Message:{0}", ex.Message.Trim()));            
	    			 }            
	    		 finally            
	    		 {                
	    			 Console.ReadLine();            
	    			 }        
	    		 }    
	     }}
	    		 }
	    	 }
	     }

  代码效果

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/35150.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注