【问题标题】:Large Data Initial Setup Pattern for Task Parallel Library任务并行库的大数据初始设置模式
【发布时间】:2016-11-18 10:29:33
【问题描述】:

对于那些希望并行化计算密集型算法的人,让我为您指出这份关于利用 .NET 4 及更高版本的任务并行库的常见模式的文档:https://www.microsoft.com/en-us/download/details.aspx?id=19222

但是,有一种我认为相当普遍的模式,我有它没有包含在那个其他很棒的文档中......

我说 DataTable 中有 100 行在 N 列中有一组输入,我需要为此计算 M 列中的一些输出。每一行都可以独立计算,所以它似乎是并行化的首要条件。

但是,要进行该计算,我需要首先构建一个海量数据结构。一旦为一行构建,我可以简单地重置它以将其用于另一行。所以,我不想为每一行从头开始重建它……这比重置要长得多。但是并行计算不能共享该数据结构,因为它们都将对其进行修改……相反,它们都需要自己的。

太棒了,从算法上讲,我需要为我可用的每个处理器内核启动一个线程,首先构建自己的海量数据结构。然后它应该计算一行,重置,计算另一行,重置,等等,直到没有更多的行要计算。

任务并行库拥有管理这样一个过程的所有智能......但我还没有找到这种场景的任何示例,我需要每个线程进行大量数据构建、计算、重置、计算、重置,依此类推,直到完成。

这似乎是一种相当常见的模式...谁能给我举个例子,说明 .NET 4 及更高版本的任务并行库如何支持该模式??

【问题讨论】:

  • 这是一种常见的气味,而不是常见的模式。如果您必须“清理和重用”相同的结构,则需要锁定。馊主意。为什么还需要预制结构?有什么好处?要么你必须替换所有值(然后创建一个新值),要么你在谈论常量值。
  • 您认为通过重用结构可以解决的实际问题是什么?您是否正在尝试减少内存消耗?分配?您可以使用技术来避免分配(例如,使用正则表达式而不是文件的字符串拆分),或者使用缓冲池来重用缓冲区。
  • 我不需要锁定,因为我计划让每个线程构建自己的基础结构实例。把它想象成世界的模型。然后每一行包含该世界中发生的事情(输入),然后需要进行大量分析以确定返回该行的结果。无需锁定。问题是,如果我有 4 个内核和 1000 行,我只想构建世界的基本模型 4 次,并让每个线程清理并重用其模型 250 次。 (我当前的顺序实现只构建了一次世界模型,然后清理和重用了 1000 次。)
  • 重用世界模型可以节省时间。想象一下,构建该基本模型需要 10 分钟,使用它来计算一行的结果需要 2 分钟,清理它需要 1 分钟。我的顺序需要 10 + 1000 * (2 + 1) = 3010 分钟。如果我通过排队 1000 个任务以在每个构建模型和分析的 4 个内核上运行来并行化它,那么它将花费 (10 + 2) * 1000 / 4 = 3000 分钟。考虑到额外的开销,净损失。如果我按照我的建议并行化它,那么所有 4 个构建基本模型加上 (2 + 1) * 1000 / 4 = 760 分钟需要 10 分钟......非常接近 4 倍的加速。如何在 TPL 中进行设置?

标签: .net parallel-processing task-parallel-library large-data


【解决方案1】:

我想出的最佳答案是…… 如果您有更好的...或者您是否可以看到其中的缺陷,请告诉我...

我想我需要调用 Parallel.For(0, Environment.ProcessorCount, ...) 并让该代码构建基本结构,然后通过对共享 rowIndex 执行 Interlocked.Increment 开始处理行,直到所有行都已处理。

这样,基本结构最多为每个处理器构建一次,然后重复使用......但如果这开始消耗过多的内存或其他资源,那么 Parallel.For 可以选择运行少于 Environment.ProcessorCount一次完成任务。是吗?

有没有更好的办法?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-12
    • 1970-01-01
    • 1970-01-01
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多