CLR Via笔记之.NET 4.0 并行Parallel

       4.0特性中扩展了并行任务处理,其实就是封装了ThreadPool的Task。园子里有很多介绍Parallel的并行计算,其实我更看好并行查询PLINQ。 做过复杂SQL拼接报表的人应该深有体会,当复杂的SQL执行时间过长,你怎么做呢?当存储过程优化后的执行时间还是让人无法接受呢? 之前的解决方案是将复杂的SQL拆分成几段(可能是多张表)分别并行执行,将查询结果加载至内存,利用LINQ处理获取交集数据最终达到目的,当然这个是牺牲内存的方式达到目的,但是如果查询的数据短期不会有太大变化时,这种方式解决查询速度过慢肯定是个较好的方案。而PLINQ在此基础上又进一步扩大了LINQ战果。下面是PLINQ 150W条记录查询测试代码与结果

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity;
using ECEPDI.Document.Application.FileModule;
using ECEPDI.Document.Infrastructure.UnitOfWork;
using ECEPDI.Document.Infrastructure.Repositories;
using ECEPDI.Document.Domain.Entities;
using System.Threading.Tasks;
using System.Diagnostics;

namespace ScanFileUploadDemo
{
class Program
{
static void Main(string[] args)
{
ScanFileRepository processRepository = Container.Current.Resolve(typeof(ScanFileRepository)) as ScanFileRepository;
Stopwatch sw = new Stopwatch();
sw.Start();
var query = processRepository.GetFiltered(o => o.FileName.Contains("F201502S-K0518"));
Console.WriteLine("直接查询结果:" + query.Count().ToString());
sw.Stop();
Console.WriteLine("直接查询数据用时:" + sw.ElapsedMilliseconds / 1000d);


sw.Reset();
sw.Start();
List<ScanFile> list = processRepository.GetAll().ToList();
sw.Stop();
Console.WriteLine("加载数据用时:" + sw.ElapsedMilliseconds / 1000d);



Console.WriteLine("-------------------------------------------------");
sw.Reset();
sw.Start();
var result = from u in list
where u.FileName.Contains("F201502S-K0518")
select u;
Console.WriteLine("单行查询结果:" + result.Count().ToString());
sw.Stop();
Console.WriteLine("单行查询用时:" + sw.ElapsedMilliseconds / 1000d);

Console.WriteLine("-------------------------------------------------");
sw.Reset();
sw.Start();
var result2 = from u in list.AsParallel()
where u.FileName.Contains("F201502S-K0518")
select u;
Console.WriteLine("并行查询结果:" + result2.Count().ToString());
sw.Stop();
Console.WriteLine("并行查询用时:" + sw.ElapsedMilliseconds / 1000d);

Console.ReadLine();
}

}
}

用时情况:

直接查询结果是生成SQL语句到数据库中查询,结果为5.453 而数据库直接执行相同SQL语然却用时7秒

LINQ内存单行查询结果仅为0.31秒 ,但是前提是数据必须加载到内存中。

PLINQ内存并行查询结果为0.114秒 ,优势非常明显。但是PLINQ并行查询结果排列是无序的(打乱了原先的单行查询结果的顺序),由于每个线程完成时间不一致,导致多个线程查询后合并的结果是无序的。

PLINQ提供了对查询结果的再排序AsOrdered ,当然这会损失一点优势。

 

Parallel.For/Parallel.ForEach 在现有的情况中很难表现中并行的优势,相比Parallel.Invoke的却有很多的表现机会。对于并行查询和并行任务的应用性能效率提高需要要远多于For/Foreach情况。

Parallel.Invoke 同Tasks一样,在并行任务处理中是个好的选择。

    Test1();
Test2();
Test3();

//3件事同时做肯定要比一件一件来的快嘛
Parallel.Invoke(
() => Test1(),
() => Test2(),
() => Test3());


//Parallel.For/Parallel.Foreach 在普通的遍历中并不能发挥的太多的优势 (以下情况反而不如For/Foreach)
Stopwatch sw = new Stopwatch();
sw.Start();
for (Int32 i = 0; i < 1000; i++) DoWork(i);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds / 1000d);


sw.Reset();
sw.Start();
Parallel.For(0, 1000, i => DoWork(i));
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds / 1000d);

var collection = new Int32[0];
sw.Reset();
sw.Start();
foreach (var item in collection) DoWork(item);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds / 1000d);

sw.Reset();
sw.Start();
Parallel.ForEach(collection, item => DoWork(item));
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds / 1000d);

 

PS:复杂的SQL语句以及存储过程报表,在写的时候非常清楚,但是过段时间再回来改的时候连自己也看不懂了-_-|||。

posted on 2011-11-16 11:56  小城岁月  阅读(927)  评论(1编辑  收藏  举报

导航

面朝大海,春暖花开!