并行运算学习(1)

news/2024/10/17 21:20:41/

     最近有项目对于性能要求非常高,虽然系统大部分都是IO密集型,但也不排除有计算密集型的操作,比如将来在项目中采用了Mongdb,那么将会有非常多的机会对大的泛型集合进行查询,计算(比如sum操作)等,多少能起到一定的性能提升作用,多核心CPU如果不充分利用起来实在有些可惜。
    
     文中的部分代码均参考Parallel Programming with Microsoft .NET,这篇文章是以第五章后面的习题来分享。题目给了一个思路,对于一个过程是否可以采取并行运算,最好事先画一张流程图,看看哪些部分是可以并行的,即之间没有任何的依赖关系,图中能放在一个水平线上的即表示可以并行的部分。

                                                                    
     说明:

         1:本文的代码不考虑IO,即全部代码都是在CPU中执行,对于有IO的情况,会在后面的文章中做充分的尝试。
         2:测试环境是:Intel(R) Core(TM)2 Duo CPU T9550 @2.66GHZ


     题目:将下面代码并行起来。
     var b = F1(a);  var d = F2(c);  var e = F3(b,d);  var f = F4(e);  var g = F5(e); var h = F6(f,g);
    
     首先我们来看下这6个函数的执行流程图,图中箭头代表依赖方向,线上的字母分别代表输入输出参数。
                                                                
     分析:从图中可以看出,F1,F2在同一水平线了,同样,F4,F5也在同一水平线上,这说明这两部分是可以并行的。
    
     测试的核心函数是一个数字累加的过程:

    

ExpandedBlockStart.gif View Code
///   <summary>
        
///  Simulates a CPU-intensive operation on a single core. The operation will use approximately 100% of a
        
///  single CPU for a specified duration.
        
///   </summary>
        
///   <param name="seconds"> The approximate duration of the operation in seconds </param>
        
///   <returns> true if operation completed normally; false if the user canceled the operation </returns>
         public   static   bool  DoCpuIntensiveOperation( double  seconds)
        {
            
return  DoCpuIntensiveOperation(seconds, CancellationToken.None,  false );
        }

        
///   <summary>
        
///  Simulates a CPU-intensive operation on a single core. The operation will use approximately 100% of a
        
///  single CPU for a specified duration.
        
///   </summary>
        
///   <param name="seconds"> The approximate duration of the operation in seconds </param>
        
///   <param name="token"> A token that may signal a request to cancel the operation. </param>
        
///   <param name="throwOnCancel"> true if an execption should be thrown in response to a cancellation request. </param>
        
///   <returns> true if operation completed normally; false if the user canceled the operation </returns>
         public   static   bool  DoCpuIntensiveOperation( double  seconds, CancellationToken token,  bool  throwOnCancel  =   false )
        {
            
if  (token.IsCancellationRequested)
            {
                
if  (throwOnCancel)
                    token.ThrowIfCancellationRequested();
                
return   false ;
            }

            
long  ms  =  ( long )(seconds  *   1000 );
            Stopwatch sw 
=   new  Stopwatch();
            sw.Start();
            
long  checkInterval  =  Math.Min( 20000000 , ( long )( 20000000   *  seconds));

            
//  loop to simulate a computationally intensive operation
             int  i  =   0 ;
            
while  ( true )
            {
                i 
+=   1 ;

                
//  periodically check to see if the user has requested cancellation 
                
//  or if the time limit has passed
                 if  (seconds  ==   0.0d   ||  i  %  checkInterval  ==   0 )
                {
                    
if  (token.IsCancellationRequested)
                    {
                        
if  (throwOnCancel) token.ThrowIfCancellationRequested();
                        
return   false ;
                    }

                    
if  (sw.ElapsedMilliseconds  >  ms)
                        
return   true ;
                }
            }
        }


     6个函数内容如下,基本就是些加减法:

         

ExpandedBlockStart.gif View Code
///   <summary>
        
///  A computationally intensive function
        
///   </summary>
         static   int  F1( int  value)
        {
            SampleUtilities.DoCpuIntensiveOperation(
2.0 );
            
return  value  *  value;
        }

        
///   <summary>
        
///  A computationally intensive function
        
///   </summary>
         static   int  F2( int  value)
        {
            SampleUtilities.DoCpuIntensiveOperation(
1.0 );
            
return  value  -   2 ;
        }
        
///   <summary>
        
///  A computationally intensive function
        
///   </summary>
         static   int  F3( int  value1,  int  value2)
        {
            SampleUtilities.DoCpuIntensiveOperation(
0.1 );
            
return  value1  +  value2;
        }
        
///   <summary>
        
///  A computationally intensive function
        
///   </summary>
         static   int  F4( int  value)
        {
            SampleUtilities.DoCpuIntensiveOperation(
1.0 );
            
return  value  +   1 ;
        }

       
        
///   <summary>
        
///  A computationally intensive function
        
///   </summary>
         static   int  F5( int  value)
        {
            SampleUtilities.DoCpuIntensiveOperation(
1.0 );
            
return  value  +   5 ;
        }
        
///   <summary>
        
///  A computationally intensive function
        
///   </summary>
         static   int  F6( int  value1,  int  value2)
        {
            SampleUtilities.DoCpuIntensiveOperation(
1 );
            
return  value1  +  value2;
        }


     为了做对比,我分别做了以下几部分测试:
     1:传统的顺序计算;  
     2:只将F1并行起来;
     3:只将F4并行起来;
     4:将F1,F4都并行起来。
      

///   <summary>
        
///  Sequential example
        
///   </summary>
         public   static   int  Example1()
        {
            var a 
=   22 ;
            var c 
=   11 ;
            var b 
=  F1(a);
            var d 
=  F2(c);
            var e 
=  F3(b,d);
            var f 
=  F4(e);
            var g 
=  F5(e);
            var h 
=  F6(f, g);
            
return  h;
        }

        
///   <summary>
        
///  A parallel example that uses the futures pattern for F1
        
///   </summary>
         public   static   int  Example2()
        {
            var a 
=   22 ;

            var bf 
=  Task < int > .Factory.StartNew(()  =>  F1(a));
            var c 
=  F2( 11 );
            var d 
=  F3(bf.Result,c);
            var f 
=   F4(d);
            var g 
=  F5(d);
            var h 
=  F6(f , g);
            
return  h;
        }
        
///   <summary>
        
///  A parallel example that uses the futures pattern for F4
        
///   </summary>
         public   static   int  Example3()
        {
            var a 
=   22 ;

            var b 
=   F1(a);
            var c 
=  F2( 11 );
            var d 
=  F3(b, c);
            var f 
=  Task < int > .Factory.StartNew(()  =>  F4(d));
            var g 
=  F5(d);
            var h 
=  F6(f.Result, g);
            
return  h;
        }
        
///   <summary>
        
///  A parallel example that uses the futures pattern for F1/F4
        
///   </summary>
         public   static   int  Example4()
        {
            var a 
=   22 ;

            var bf 
=  Task < int > .Factory.StartNew(()  =>  F1(a));
            var c 
=  F2( 11 );
            var d 
=  F3(bf.Result, c);
            var f 
=  Task < int > .Factory.StartNew(()  =>  F4(d));
            var g 
=  F5(d);
            var h 
=  F6(f.Result, g);
            
return  h;
        }

        
        测试结果:从下图可以非常清晰的看出,在使用并行后,性能得到了明显的提升,如果在release下应该效果会更好。

       
                                        
       

       下面的一个测试,只是写法上的不同,从理论上来讲,和Example4对比没有实质的性能提升。如果两个任务可以并行,我们将其中一个task用并行模式即可。
         

///   <summary>
        
///  些种写法只是做一个对比,理论上没有性能提升
        
///   </summary>
         public   static   int  Example5()
        {
            var a 
=   22 ;

            var bf 
=  Task < int > .Factory.StartNew(()  =>  F1(a));
            var c 
=  Task < int > .Factory.StartNew(()  =>  F2( 11 ));
            var d 
=  F3(bf.Result, c.Result);
            var f 
=  Task < int > .Factory.StartNew(()  =>  F4(d));
            var g 
=  F5(d);
            var h 
=  F6(f.Result, g);
            
return  h;
        }

      执行的测试结果图如下:

                                        

 

    总结:并行运算是个好东西,主要是需要搞清楚它的适用场景,它主要针对计算型的运算,如果都是些数据库操作之类的IO访问,作用并不是特别大,如果处理的数据量不大,性能也不会有提升,反而也许会有影响,创建线程也是需要开销的,核心的就是确认好适用场景,然后是确认可以并行的部分。对于IO操作,下面的内容我会根据实际情况做些测试,本文有什么不对的地方,希望大家批评指正。

转载于:https://www.cnblogs.com/ASPNET2008/archive/2011/07/31/2123201.html


http://www.ppmy.cn/news/386842.html

相关文章

电机扭矩计算公式T=9550*P/n

功率是指单位时间内做功的大小。功是力乘以作用的距离&#xff0c;功率公式就表示为&#xff1a;P&#xff08;FS&#xff09;&#xff0f;&#xff54;&#xff1b;&#xff08;&#xff26;是做功的力&#xff0c;S是距离&#xff0c;&#xff54;是时间&#xff09;。由于距…

9550电机_电机扭矩计算公式里面的9550*P是怎么得来的?

先&#xff0c;减速器会改变扭矩和转速&#xff0c; T转矩单位Nm&#xff0c;不会改变功率&#xff0c;如果考虑减速器的效率&#xff0c; 那么就是如下公式&#xff1a; P*1000π/3;R ---公式2 线速度(V)2πR*每秒转速(n秒)2πR*每分转速(n分)/60 πR*n分/30---公式3 将公式2、…

9550电机_电机 9550怎么来的

展开全部 电机的额定转矩为Tn&#xff1d;9550*Pn/nN &#xff0c;推证如下&#xff1a; 由运动学的知识我们知道PFv&#xff0c;P是功率&#xff0c;F是力&#xff0c;v是物体运行的速度&#xff0c;62616964757a686964616fe4b893e5b19e31333431366264功率力*速度 PF*V。 假设…

9550电机_电机转矩T=9550*P/N推导。

很奇怪&#xff0c;这个公式怎么来的&#xff0c;原来好多是基础物理的&#xff0c;也许我们初中高中物理书上多有&#xff0c;基础真的是很基础的基础。 PF*V (1) ,即功率力*速度 TF*R (2) ,即力矩力*作用长度 &#xff0c;在电机里面就是转矩力*作用半径&#xff1b; 看公式…

英特尔支持虚拟化技术处理器列表

转自http://sq.eq2012.info/sq/read.php?tid1552 Intel Virtualization Technology ListYES表示支持虚拟化技术&#xff0c;NO表示不支持。 Intel Atom™ ProcessorProcessor # Supports Intel VT-x230 No 330 No D410 / D425 No D510 / D525 No E620 / E620T / E64…

CPU T9500-p9500-T9400-T9300-p8700各种小黑主流处理器对比分析

许多入门本友会对处理器是P和T开头含混不清&#xff0c;不甚了解&#xff0c;也怪英特尔的处理器型号实在是太过复杂。所以 产生了究竟是日产好还是本田好的疑惑。这需要具体型号来看的。让我们先来看看英特尔的官方解释吧 T: Mobile Highly Performance——偏重于高性能 P…

帮你选处理器:CPU T9500-p9500-T9400-T9300-p8700对比分析!

许多人对处理器是P和T开头含混不清,不甚了解,也怪英特尔的处理器型号实在是太过复杂。这需要具体型号来看的。让我们先来看看英特尔的官方解释吧 T: Mobile Highly Performance——偏重于高性能 P: Power Optimized Energy Efficient higher Performance——偏重于高效能 SP:…

【Flutter】Flutter 创建每个页面公用的底部框

文章目录 一、 前言二、 创建公用底部框的步骤1. 创建一个公用的底部框 Widget2. 在页面中使用公用的底部框 Widget 三、 示例&#xff1a;电商应用中的公用底部框1. 创建电商应用的底部框 Widget2. 在电商应用的各个页面中使用底部框 Widget 四、 完整代码示例五、 一些注意事…