【问题标题】:Fastest Way to Parse Large Strings (multi threaded)解析大字符串的最快方法(多线程)
【发布时间】:2010-11-06 18:31:05
【问题描述】:

我即将开始一个项目,该项目将获取文本块,将大量数据解析为某种对象,然后可以对其进行序列化、存储和统计/数据收集。这需要尽可能快,因为我需要开始处理超过 10,000,000 个文本块,并且每天将获得 100,000 个。

我在具有 12 个至强内核 + 超线程的系统上运行它。我也可以访问/了解一点关于 CUDA 编程的知识,但对于字符串的东西,我认为它不合适。从每个字符串中,我需要解析大量数据,其中一些我知道确切的位置,有些我不知道,需要使用正则表达式 / 一些聪明的东西。

所以考虑这样的事情:

object[] parseAll (string [] stringsToParse)
{
     parallel foreach 
          parse( string[n] )
}

object parse(string s)
{
     try to use exact positions / substring etc here instead of regex's
}

所以我的问题是:

  • 使用正则表达式的 substr.
  • .NET 会比其他语言慢很多吗?
  • 我可以进行哪些优化(如果有)来最大化并行度。
  • 还有什么我没有考虑过的吗?

感谢您的帮助!很抱歉,如果这是冗长的。

【问题讨论】:

  • 我的猜测是 IO 将成为限制因素。设置一些简单的测试用例并分析您的资源使用情况等。
  • 在现代 PC 上,您所说的卷对于数据仓库工作来说是小菜一碟。你提出的方法听起来,呃,好的。当您知道可以安全地搜索固定字符串时,还可以考虑使用 IndexOf 之类的东西。如果比较函数支持忽略大小写,请尽可能避免使用 ToUpper/Lower。但首先,为了可读性而编写,然后进行优化。

标签: c# regex parsing string parallel-processing


【解决方案1】:

使用正则表达式的 substr 会慢多少。
如果您正在寻找一个精确的字符串, substr 会更快。然而,正则表达式是高度优化的。它们(或至少部分)被编译为 IL,您甚至可以使用 Regex.CompileToAssembly 将这些编译版本存储在单独的程序集中。请参阅http://msdn.microsoft.com/en-us/library/9ek5zak6.aspx 了解更多信息。

您真正需要做的是进行测量。到目前为止,使用 Stopwatch 之类的东西是验证一个或另一个代码结构是否运行得更快的最简单方法。

我可以进行哪些优化(如果有)来最大化并行性。
使用Task.Factory.StartNew,您可以安排任务在线程池上运行。您还可以查看 TPL(任务并行库,Task 是其中的一部分)。这有很多构造可以帮助您并行化工作,并允许像Parallel.ForEach() 这样的构造在多个线程上执行迭代。请参阅http://msdn.microsoft.com/en-us/library/dd460717.aspx 了解更多信息。

还有什么我没有考虑过的吗?
这种数据量会伤害您的一件事是内存管理。需要考虑的几点:

  • 限制内存分配:尝试为单个文档重复使用相同的缓冲区,而不是在只需要一部分时复制它们。假设您需要处理从 char 1000 到 2000 开始的范围,不要将该范围复制到新缓冲区中,而是构建您的代码以仅在该范围内工作。这将使您的代码更复杂,但可以节省内存分配;

  • StringBuilder 是一个重要的类。如果您还不知道,请看一下。

【讨论】:

  • 完全同意。特别要注意内存分配部分。对于如此大的容量,可能会遭受内存碎片的影响。如果您还没有阅读并理解这一点,我建议您阅读并理解:simple-talk.com/dotnet/.net-framework/…
【解决方案2】:

我不知道您在这里进行什么样的处理,但如果您每天要处理数十万个字符串,这似乎是一个很小的数字。假设您每天要处理 100 万个新字符串,您可以完全处理这 12 个 Xeon 内核中的 10 个。也就是说,每个核心每天有 100,000 个字符串。一天有 86,400 秒,所以我们说的是每个字符串 0.864 秒。这是很多的解析。

我会回应@Pieter 提出的建议,尤其是在他建议进行测量以了解您的处理需要多长时间的情况下。最好的办法是启动并运行某些东西,然后在需要时找出如何让它更快。我想你会惊讶于你不需要做任何优化的频率。 (我知道这对优化向导来说是异端,但处理器时间很便宜,而程序员的时间很贵。)

使用正则表达式的 substr 会慢多少?

这完全取决于您的正则表达式的复杂程度。正如@Pieter 所说,如果您正在寻找单个字符串,String.Contains 可能会更快。如果您正在寻找常量字符串,您也可以考虑使用String.IndexOfAny。除非您正在寻找无法表示为常量字符串的模式,否则不需要正则表达式。

.NET 会比其他语言慢很多吗?

在处理器密集型应用程序中,.NET 可能比本机应用程序慢。有时。如果是这样,它通常在 5% 到 20% 的范围内,最常见的是在 7% 到 12% 之间。这只是孤立执行的代码。您必须考虑其他因素,例如用其他语言构建程序需要多长时间,以及在本机应用程序和系统其他部分之间共享数据的难度。

【讨论】:

  • 您的计算假设完美分布与时间。在许多情况下,他的负载在高峰时段可能会增加一倍或更多。 (这仍然可能不是大量的处理时间,但是当您只有 1/10 所需的统计数据来实际解决问题/告诉他是否需要购买更多服务器时,没有理由在某事上投入数学:)。跨度>
  • @Merlyn:是的,我忽略了峰值。我也高估了每天的负荷。此外,没有提到需要“实时”。我将这个问题解释为“我如何跟上负载?”我的回答反映了这一点。是的,在高峰期可能会有物品留在队列中。但这几乎总是如此,除非您为高峰期设计系统,这意味着您在非高峰期有空闲的硬件。
  • 是的。这一切都取决于他的真正要求是什么。 “尽可能快”表明他想要一个好的响应时间,或者至少是好的周转时间,但这也表明他不知道为了保证任何特定的服务水平他需要查看什么。我认为给出数学与他现在拥有的数据可能会给他一种错误的安全感,即他已经正确检查了他的要求,并将满足这些要求。顺便说一句,我也在考虑网络服务。他的应用可能无法反映这一点,在这种情况下,简单的性能指标可能就可以了。
【解决方案3】:

Google 最近宣布了它的内部文本处理语言(它看起来像是为高度并行处理而设计的 Python/Perl 子集)。

http://code.google.com/p/szl/ - Sawzall。

【讨论】:

    【解决方案4】:

    如果您想在 C# 中进行快速字符串解析,您可能需要考虑查看新的 NLib 项目。它包含字符串扩展,以方便以各种方式快速搜索字符串。例如,IndexOfAny(string[]) 和 IndexOfNotAny。它们也包含带有 StringComparison 参数的重载。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-21
      • 2013-05-26
      • 2017-04-25
      • 1970-01-01
      • 1970-01-01
      • 2012-02-04
      • 1970-01-01
      相关资源
      最近更新 更多