并行是指多个工作任务在多核宿主机上同时执行。执行是真正意义上的同步,而非分片的。
并行计算的优势就在于它可以缩短系统完成单个工作任务(该任务可能包含多个步骤,或则说该任务由多个Action组成)的时间和提升系统的吞吐率。
主要的并行计算结构类型可分为:共享存储器的多核处理器和多存储器多核的计算系统(集群化)。在编程方面,在.Net4.0中新加的并行扩展(Parallel)能帮助我们使用一种非常简单的方式进行共享存储器模式下的并行编程。而对于多存储器多核的系统,WCF能帮助我们轻松的达到并行化目的。
接下来简单介绍使用Parallel在共享存储器的多核处理器系统中实现并行化。
Parallel.For 并行执行任务:
System.Threading.Tasks.Parallel.For(0, 20,
(i) => { Console.WriteLine(i); });
很简单的一句话,并行输出0到20个数字。此外还有For<T> Foreach<T>方法。使用方法大致相同。
Parallel.Invoke 尽量并行执行任务
System.Threading.Tasks.Parallel.Invoke(
() => { Console.WriteLine("并行任务之一"); },
() => { Console.WriteLine("并行任务之一"); },
() => { Console.WriteLine("并行任务之一"); },
() => { Console.WriteLine("并行任务之一"); });
同样,非常简单的一条语句。此外,Invoke方法还存在一个参数:ParallelOptions。我们可以使用他来中断并行任务:
CancellationTokenSource cts = new CancellationTokenSource();//取消并行运算需要的类
ParallelOptions pOption = new ParallelOptions()
{
CancellationToken = cts.Token
}; //并行运算选项
pOption.MaxDegreeOfParallelism = 10; //一个并行最多开启10条线程执行
Console.WriteLine("开始执行,3.5 秒后结束");
Task tasks = new Task(() =>
{
Task.Factory.StartNew(() =>
{
Thread.Sleep(3500);
cts.Cancel();
Console.WriteLine("取消并行运算");
});
});
System.Threading.Tasks.Parallel.Invoke(pOption,
() => Task1(pOption.CancellationToken),
() => Task2(pOption.CancellationToken)); //并行执行Task1和Task2
private static void Task1(CancellationToken token)
{
// 每隔 1 秒执行一次,直到此任务收到了取消的请求
while (!token.IsCancellationRequested)
{
Console.WriteLine("Task1 - " + "ThreadId: " + Thread.CurrentThread.ManagedThreadId.ToString());
Thread.Sleep(1000);
}
}
private static void Task2(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
Console.WriteLine("Task2 - " + "ThreadId: " + Thread.CurrentThread.ManagedThreadId.ToString());
Thread.Sleep(1000);
}
}
PLINQ,LINQ这个词太可爱了(^_^)。它大大减轻了我们的筛查操作。
PLINQ顾名思意就是使用并行的方式进行LINQ查询。(是不是很酷!) 但是很遗憾,这里的并行只能进行Linq-To-Object查询。就是说执行并行Linq内存中的数据(*_*)。不过即使只是Linq-To-Object
也很惹人喜爱。
var source = Enumerable.Range(1, 99).OrderBy(c=>c);
var sort = from c in source.AsParallel<int>()
where c % 2 == 0
select c;
简单的一句话:AsParallel() 告诉程序,并行的执行LINQ操作。但并行的结果是,原有的顺序被打乱了。好在我们任有办法解决它:
var source = Enumerable.Range(1, 99).OrderBy(c=>c);
var sort = from c in source.AsParallel<int>()
where c % 2 == 0
orderby c
select c;
对于一个序列进行Linq操作的时候可能会需要一段进行并行操作,一段进行串行操作。那么使用PLINQ可能会存在困难,无妨,我们还有扩展方法(^_^):
var source = Enumerable.Range(1, 99).OrderBy(c=>c);
var sort = source
.AsParallel<int>()
.Where(c => c % 2 == 0)
.OrderBy(c => c)
.AsSequential<int>()
.Select(c => c);
我们还可以告诉程序。我们需要维持数据的原有顺序:
var source = Enumerable.Range(1, 99).OrderBy(c=>c);
var sort = from c in source.AsParallel<int>().AsOrdered<int>()
where c % 2 == 0
select c;
AsOrdered()和AsSequential()是不一样的,AsSequential()强制PLINQ查询以串行方式执行,而AsOrdered()仍是并行执行的,只不过并行执行的结果先被缓存起来,然后再按原始数据顺序进行排序,才得到最后的结果。
很明显,给PLINQ查询加上AsOrdered()子句将会影响到程序的性能,因此,尽量避免使用它。最直接的解决方案是:
var sort = from c in source.AsParallel<int>()
where c % 2 == 0
orderby c
select c;
这只是PLINQ的'一个脚趾头'。Linq-To-Object能实现的东西PLINQ基本上都能搞定