【发布时间】:2016-05-12 01:03:12
【问题描述】:
我编写了一个非常简单的“字数统计”程序,它读取文件并计算文件中每个单词的出现次数。以下是部分代码:
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 的运行时是否存在缺陷?
提前致谢。
【问题讨论】:
-
您可以从http://norvig.com/big.txt下载一个 6 MB 的文本文件
-
第一条线索:根据输入 List 创建一个 ReadOnlyCollection 并在您的委托中使用它
-
您意识到您选择的添加延迟的方法会增加明显的 CPU 利用率吗?您是否使用资源监视器来了解 CPU、I/O 和内存利用率?
-
@HABO 我使用Process Explorer。但正如我所说,运行多个进程会产生更好的结果!
-
Environment.ProcessorCount 将为您提供系统中虚拟处理器的数量,这可能不是您的进程可用的处理器数量。
标签: c# .net multithreading task-parallel-library multiprocessing