如何使用C#和并行扩展来并行化顺序任务?

3
我有以下一系列按顺序调用的方法:
  1. private StringBuilder ReadPDF();
  2. private StringBuilder CleanText(StringBuilder sb);
  3. private void ParseText();
ParseText调用ReadPDF,而ReadPDF又调用CleanText。
我要解析的PDF文件有15MB文本,使用普通的Core 2 Duo计算机提取所有数据需要10分钟。
如何并行化这些任务?
编辑:为了澄清,读取PDF需要很少的时间。问题在于解析提取的文本,具体来说是在CleanText阶段。我需要并行化的原因是清理单个页面是瞬间完成的,但清理超过2000页需要很长时间。
3个回答

2

首先,您可能需要检查一下阅读PDF的方式。如果它只有15MB,除非您使用某种非常糟糕的解析方式,否则不可能需要10分钟才能读完。 其次,在找到更好的解析方式之后,您应该确保可以从任何需要的页面逐页阅读。然后,您就可以并行运行多个任务以阅读单个页面。


阅读PDF并不需要10分钟,通常每2k页需要大约10秒钟,因为我会保留文档结构进行阅读。14分钟所花费的时间是清理文本。 - anthony
@anthony,CleanText的作用是什么让它执行得这么慢?再一次,我无法想象出任何一个处理过程应该花费这么长的时间,即使它对文本进行了"视频"处理。 - Denis Mazourick
其实这是我的错误。我一直在整个文本中寻找一个匹配项,并为每个所需的匹配项重复这个过程。由于文本非常难以解析(没有模式),所以花费的时间很长。我听从了你的建议,将单个页面的并行解析将解析时间从10多分钟缩短到了6秒钟。 - anthony

1

抱歉,我应该说一下,读取PDF文件是很快的,问题在于清理它以便提取我所需的数据。 - anthony
哇,流水线处理正是我需要的:使用其他任务输出来生成最终结果的任务,对吗?! - anthony
我尽可能地使用字符串构建器来限制新创建的字符串。这是我用来清理文本的简化版本代码:http://pastebin.com/TBFpnMxQ - anthony
只有在内部缓冲区当前为单个字符串时才会这样做。如果您对SB进行了任何编辑,则可能不是这种情况。因此,它需要首先将缓冲区收集到单个字符串中,然后再将其引用返回。这样做需要制作所有数据的全新副本,对于大量文本来说,这将非常耗时。相反,当您处理大量文本时,最好将其分成较小的块。这样,编辑不会使任何更多的内容无效,而仅使正在编辑的块无效,而不是整个几兆字节的RAM块。 - Sean U
更正之前的评论:我刚刚在Reflector中仔细检查了StringBuilder的工作方式,在.NET 4中至少看起来StringBuilder.ToString()总是会分配一个全新的字符串。 - Sean U
显示剩余3条评论

0

正如Denis所说,您可以阅读文本的一部分,通常是一页,但您可能能够将其分成更小的块,然后在阅读下一部分文本时处理该文本。

如果您想了解更多关于并行编程的信息,您可以在MSDN并行计算中心找到好的信息和实验室。

MDN还有一个.NET并行编程博客

Gastón Hillar的一本好书是 Professional Parallel Programming with C#: Master Parallel Extensions with .NET 4。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接