先看LINQ的方式,dynamic的方式:
void Main()
{
// testing setup
var source = Enumerable.Range(0, 10000000).ToArray();
double[] results = new double[source.Length];
Console.WriteLine("creating partitioner in LINQ way...");
var dt = DateTime.Now;
var partitionerLinq = Partitioner.Create(source, true);
Console.WriteLine("creating partitioner in LINQ done, ticks: " + (DateTime.Now - dt).Ticks);
dt = DateTime.Now;
var r = partitionerLinq.AsParallel().Select(x => x * x * Math.PI).ToList();
Console.WriteLine("LINQ way done , ticks:" + (DateTime.Now - dt).Ticks);
dt = DateTime.Now;
for(var i = 0;i < source.Length; i++){
results[i] = source[i] * Math.PI;
}
Console.WriteLine("processing by single thread done, ticks : " + (DateTime.Now - dt).Ticks);
}
LINQPAD输出:
creating partitioner in LINQ way...
creating partitioner in LINQ done, ticks: 0
LINQ way done , ticks:3472754
processing by single thread done, ticks : 380298
可见,动态分配chunk的partition基本比单线程的普通实现慢了10倍!
再看静态的方式:
void Main()
{
// testing setup
var source = Enumerable.Range(0, 10000000).ToArray();
double[] results = new double[source.Length];
Console.WriteLine("creating partitioner in a way processing as static range ..");
var dt = DateTime.Now;
// Partition the entire source array.
var rangePartitioner = Partitioner.Create(0, source.Length);
Console.WriteLine("created partitioner, ticks:" + (DateTime.Now - dt).Ticks);
dt = DateTime.Now;
// Loop over the partitions in parallel.
Parallel.ForEach(rangePartitioner, (range, loopState) =>
{
// Loop over each range element without a delegate invocation.
for (int i = range.Item1; i < range.Item2; i++)
{
results[i] = source[i] * source[i] * Math.PI;
}
});
Console.WriteLine("processing by range partitioner done, ticks : " + (DateTime.Now - dt).Ticks);
dt = DateTime.Now;
for(var i = 0;i < source.Length; i++){
results[i] = source[i] * Math.PI;
}
Console.WriteLine("processing by single thread done, ticks : " + (DateTime.Now - dt).Ticks);
}
// Define other methods and classes here
LINQPAD输出:
creating partitioner in a way processing as static range ..
created partitioner, ticks:0
processing by range partitioner done, ticks : 185180
processing by single thread done, ticks : 375279
基本上,静态partition的方式比普通方式快两倍。
现在,依然使用静态方式,把数据量增大10倍,看LINQ输出:
creating partitioner in a way processing as static range ..
created partitioner, ticks:0
processing by range partitioner done, ticks : 1951457
processing by single thread done, ticks : 3808162
可以看到,时间差别依然差不多是一倍的速度。
总结,当考虑使用Partition时,最好使用静态方式;并且处理逻辑不建议过于复杂(MSDN建议:In general, range partitioning is only faster when the execution time of the delegate is small to moderate);不过这一点还有待测试,暂时没有想出合适的logic来测试。