我已经编写了一个非常简单的“字数”程序,读取一个文件,并在文件中计算每个单词的出现。 下面是代码的一部分:
class Alaki
{
private static List<string> input = new List<string>();
private static void exec(int threadcount)
{
ParallelOptions options = new ParallelOptions();
options.MaxDegreeOfParallelism = threadcount;
Parallel.ForEach(Partitioner.Create(0, input.Count),options, (range) =>
{
var dic = new Dictionary<string, List<int>>();
for (int i = range.Item1; i < range.Item2; i++)
{
//make some delay!
//for (int x = 0; x < 400000; x++) ;
var tokens = input[i].Split();
foreach (var token in tokens)
{
if (!dic.ContainsKey(token))
dic[token] = new List<int>();
dic[token].Add(1);
}
}
});
}
public static void Main(String[] args)
{
StreamReader reader=new StreamReader((@"c:\txt-set\agg.txt"));
while(true)
{
var line=reader.ReadLine();
if(line==null)
break;
input.Add(line);
}
DateTime t0 = DateTime.Now;
exec(Environment.ProcessorCount);
Console.WriteLine("Parallel: " + (DateTime.Now - t0));
t0 = DateTime.Now;
exec(1);
Console.WriteLine("Serial: " + (DateTime.Now - t0));
}
}
它是简单和直截了当。 我使用字典来计算每个单词的出现。 风格大致基于MapReduce的编程模型。 正如你所看到的,每个任务使用自己的私人字典。 因此,不存在共享变量; 只是一堆,通过自己算话的任务。 下面是当该代码是一个四核i7的CPU上运行的输出:
并行:00:00:01.6220927
串行:00:00:02.0471171
加速比约为1.25,这意味着一个悲剧! 但是,当我处理每个行,当添加一些延迟,我可以约4达到加速值。
在没有延迟的原始并行执行,CPU的使用率难以到达至30%,因此,加速不希望的。 但是,当我们添加一些延迟,CPU的利用率达到97%。
首先,我认为原因是该程序的IO结合性质(但我认为插入到字典是在一定程度上CPU密集型),并且因为所有的线程从共享存储器总线读取数据似乎是合乎逻辑。 然而,令人惊讶的一点是,当我运行串行程序的4个实例(无延迟)同时,CPU的利用率达到约加薪和所有的四个实例的约2.3瞬间完成!
这意味着,当所述代码在多处理配置中运行,它达到的加速值约3.5,但是当它是在多线程的配置中运行,该加速是约1.25。
你有什么想法? 有什么错我的代码? 因为我认为这是完全没有共享数据,我认为代码将不会遇到任何争论。 是否有.NET的运行时的一个漏洞?
提前致谢。