【问题标题】:Reading flat file with delphi OmniThreadLibrary使用 delphi OmniThreadLibrary 读取平面文件
【发布时间】:2014-04-22 16:39:00
【问题描述】:

我正在使用 delphi 读取非常宽的文件

文件以逗号分隔,大部分时间都花在解析字符串上。

逻辑如下

  1. 打开文件
  2. 读线
  3. 将行拆分为记录数组
  4. 将 spitted 数组传递给下一个过程
  5. 转到第 2 步
  6. 关闭文件。

我想并行运行第 3 步,目前正在查看 OmniThreadLibrary。

最好的方法是什么?

我应该使用 Parallel For 吗?胡椒烯?还是排队?

我正在考虑使用“Parallel For”,但问题是我不知道文件有多少行

【问题讨论】:

  • 您应该问自己几个问题:1) 您的程序能否处理文件中“乱序”处理的行? 2)您对拆分数组的处理是否涉及任何 UI 更新,还是纯粹的数据更新? 3) 是什么让您认为开始运行多线程会更好/更快?记住,你会在你的程序之上增加一个很大的复杂性,如果速度提升没有得到回报,你最终会得到一个难以维护的程序,它不会比它好多少(如果有的话)单线程版本...
  • 1.乱序没问题 2. 只更新数据 3. 逐行读取文件不解析需要1分钟,解析需要20分钟(文件很宽)

标签: delphi omnithreadlibrary


【解决方案1】:

使用多线程读取文件没有任何好处。该过程的那部分是 I/O 限制的,而不是 CPU 限制的。所以你最好从一个线程中读取整个文件。

然后您需要将文件分成几行。由于存在依赖性问题,这很难再次并行执行。第 N+1 行从第 N 行结束的地方开始。在单个线程中拆分成行是最简单的。

但是您可以在 I/O 和拆分成行之间运行管道。大块读取文件(比如一次几十 KB)。并将每个块传递到管道中以被处理成行。您可能需要为在任何时候允许在管道中放置多少数据设置一个上限。否则,如果文件的读取速度快于处理速度,您可能会耗尽内存。

因此,对于此管道,您有一个读取文件的生产者和一个将文件内容拆分为行的消费者。

然后您可以运行另一个管道。在生产者端,您有上一步生成的行列表。这被推到了处理每一行的消费者的管道上。消费者将使用 parallel for 来做到这一点。

【讨论】:

  • 只是为了澄清文件是逗号分隔的,在单线程中读取文件非常快,问题是拆分逗号分隔的行需要很多时间,所以理论上并行进行这种拆分应该会加快速度向上
  • @user3428876 是的,这将是 CPU 和内存绑定,因此并行处理应该可以正常工作。优化拆分代码也可能会带来好处。
  • 我的问题是我不知道行中的文件大小,我无法为我的情况找到一个示例 PrimeCount.Value := 0; Parallel.ForEach(1, 1000000).Execute( procedure (const value: integer) begin if IsPrime(value) then PrimeCount.Increment; end; end);
  • 只知道有多少行是不够的。您还必须知道每行的开始和结束位置。但这就是我回答的第一部分的重点。当然,我假设您不想将整个文件读入内存。如果你想这样做,那么你只需阅读它并使用并行。您还没有告诉我们文件有多大。
  • 文件大约 20 gis,我不想将整个文件读入内存,将文件拆分为单独行的部分工作正常,将行拆分为记录数组的部分是非常慢。所以我的问题是当行数未知时如何并行处理
【解决方案2】:

将解析拆分为例如 10.000 行的块可能是一种选择。我不知道 OmniThread 库,所以 部分你必须自己做,但代码的基本结构是这样的:

CONST ChunkSize = 10000;

VAR ARR : ARRAY[1..ChunkSize] OF STRING;
VAR Lines : Cardinal;
VAR TXT : TextFile;
VAR FileName : STRING;

Lines:=0;
AssignFile(TXT,FileName); RESET(TXT);
WHILE NOT EOF(TXT) DO BEGIN
  IF Lines=ChunkSize THEN BEGIN
    <Do Parallel For on ARR>;
    Lines:=0
  END;
  INC(Lines);
  READLN(ARR[Lines])
END;
<Do Parallel For on ARR - only "Lines" lines>

请注意,代码假定 部分仅在数组中的所有条目都已处理后才继续。

【讨论】:

    【解决方案3】:

    您不需要知道使用 Parallel-For 的总行数,因为您可以使用阻塞集合来迭代。添加最后一行后不要错过调用 CompleteAdding。

    请注意,与线程和队列管理相比,当每个单个任务只需要少量时间时,Parallel-For 的性能可能会严重下降。

    您也可以考虑使用 BackgroundWorker 抽象并在每个 WorkItems 中安排多行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-12
      • 2011-08-16
      • 1970-01-01
      • 2014-07-20
      • 2013-08-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多