技术开发 频道

初探.NET4和VS 2010中的多核利用

  如果不保证顺序,我将获得一个随机的订单(Orders)数据集,它们可能是(也可能不是)应该先发货的五个订单,为了确保得到前五个订单,我需要在查询中增加一个Order By子句,按照日期对查询结果进行排序,当然这样就会丢掉PLINQ的一些好处。

  因为结果来自多个线程,难免不会出现异常,PLINQ不能明白“上一条”和“下一条”的概念,如果在你的循环中刚好要用到下一条项目的值时,完全有可能会遭遇错误的处理,为了让订单中的项目按照原始数据源中的顺序处理,你需要在查询中增加AsOrdered扩展。

  例如,如果我想将低于某一运费的所有订单打包到一起处理,我可能会写下面这样一个循环:

For Each ord As Order In ords    
  totFreight
+= ord.Freight    
  
If totFreight > FreightChargeLimit Then      
    
Exit For    
    
End If    
  shipOrders.Add(ord)  
Next

 

  由于并行处理返回的项目顺序不可预知,因此进入批处理的订单可能是随机的,为了保证按照原始数据源中的顺序处理返回的结果,我必须给数据源加上AsOrdered扩展。

ords = From o In re.Orders.AsParallel.AsOrdered        
   Where o.RequiredDate
> Now          
  
Select o

 

  TPL(任务并行库)介绍

  如果你的处理不是由LINQ查询驱动的,你可以使用借鉴了PLINQ的TPL技术,从根本上看,TPL让你创建可并行执行的循环,如果你的计算机是四核的,一个循环可能用1/3的时间就完成了。

  如果不使用TPL,你可能会像下面这样处理Orders集合中的所有元素:

For Each o As Order In le.Orders      
   o.RequiredDate.Value.AddDays(
2)
  
Next

 

  如果使用TPL,你调用Parallel类的ForEach方法,通过Lambda表达式来处理集合中的项目:

System.Threading.Tasks.Parallel.ForEach(    
le.Orders,
Sub(o)                    
        o.RequiredDate.Value.AddDays(
2)                
        
End Sub)

 

  通过使用Parallel ForEach,每个方法的实例可以在独立的处理器上同时处理,如果每个操作需要1毫秒,并且有足够的处理器存在,所有的订单就可以在1毫秒内处理,而不是1毫秒乘以订单数量的时间。

  任何复杂的处理放在Lambda表达式中都会变得很难阅读,因此你要经常想到在你的Lambda表达式中调用下面这样一些方法:

System.Threading.Tasks.Parallel.ForEach(    
     le.Orders,
Sub(o)                    
           ExtendOrders(o)                  
          
End Sub)  
...  
        
Sub ExtendOrders(ByVal o As Order)          
      o.RequiredDate.Value.AddDays(
2)  
      
End Sub

 

  从本质上讲,TPL将集合中的成员分配给独立的任务,这些任务又被分配到所有处理核心上执行,每个任务完成时释放掉代码,TPL调度器从执行队列中取出另一个任务开始执行,你也可以根据索引值使用For方法创建一个循环。

  当你创建自定义任务时你才会感觉到TPL的强大之处,任务创建好后使用它的Start方法启动,但它更容易使用Task类的静态工厂对象(Factory),它的StartNew方法可以创建并启动任务(Task),你只需要通过一个Lambda表达式就可以使用StartNew方法,如果你的函数要返回一个值,你可以使用Task对象的Generic版本指定返回的类型。 

0
相关文章