【发布时间】:2015-05-16 19:56:12
【问题描述】:
我正在尝试读取一个大文本文件并输出其中的不同单词及其计数。到目前为止,我已经尝试了几次,这是迄今为止我想出的最快的解决方案。
private static readonly char[] separators = { ' ' };
public IDictionary<string, int> Parse(string path)
{
var wordCount = new Dictionary<string, int>();
using (var fileStream = File.Open(path, FileMode.Open, FileAccess.Read))
using (var streamReader = new StreamReader(fileStream))
{
string line;
while ((line = streamReader.ReadLine()) != null)
{
var words = line.Split(separators, StringSplitOptions.RemoveEmptyEntries);
foreach (var word in words)
{
if (wordCount.ContainsKey(word))
{
wordCount[word] = wordCount[word] + 1;
}
else
{
wordCount.Add(word, 1);
}
}
}
}
return wordCount;
}
我如何衡量我的解决方案
我有一个 200MB 的文本,我知道它的总字数(通过文本编辑器)。我正在使用Stopwatch class 并计算单词以确保准确性并测量所用时间。到目前为止,大约需要 9 秒。
其他尝试
- 我尝试利用多线程通过 TPL 库。这涉及批处理多行,发送 将一批行处理到一个单独的任务并锁定 字典中的读/写操作。然而,这似乎不是 向我提供任何性能改进。
- 大约需要 30 秒。我怀疑锁定读/写 字典的成本太高,无法获得任何性能。
- 我也看过
ConcurrentDictionary类型,但是AddOrUpdate方法确实需要调用代码来处理 根据我的理解同步,并没有带来任何性能 受益。
我相信有更快的方法来实现这一点!有没有更好的数据结构来解决这个问题?
欢迎对我的解决方案提出任何建议/批评 - 在这里尝试学习和改进!
干杯。
更新:这是我正在使用的测试文件的link。
【问题讨论】:
-
你的源文件是什么? 200MB 的文本可能相当于整本百科全书!
-
批处理多行 也许将整体划分为核心数(n)并使用不锁定它们的n个字典会更好。然后将它们整合成一个可能会快很多,尤其是有很多重复的单词
-
这看起来可以通过 map reduce 范式有效地解决。这是一个答案,它解释了如何将 map reduce 应用于您所问的几乎相同的事情:stackoverflow.com/questions/12375761/…
-
这和我写的完全一样,一行一行:-)等等...我会使用
TryGetValue而不是ContainsKey来减少对字典的访问. -
@pwee167 出于好奇,您是否对程序读取 200mb 文件所需的时间进行了基准测试?因为200mb/9sec = 21mb/sec...已经不错了
标签: c# multithreading performance algorithm data-structures