我正在用delphi阅读非常宽的文件
该文件以逗号分隔,大部分时间用于解析字符串。
逻辑如下
- 打开文件
- 读线
- 将行拆分为记录数组
- 将吐出的数组传递给下一个过程
- 转到第 2 步
- 关闭文件。
我想并行运行第 3 步,目前正在查看 OmniThreadLibrary。
最好的方法是什么?
我应该使用 Parallel For 吗?胡椒烯?或队列?
我正在考虑使用“Parallel For”,但问题是我不知道文件有多少行
我正在用delphi阅读非常宽的文件
该文件以逗号分隔,大部分时间用于解析字符串。
逻辑如下
我想并行运行第 3 步,目前正在查看 OmniThreadLibrary。
最好的方法是什么?
我应该使用 Parallel For 吗?胡椒烯?或队列?
我正在考虑使用“Parallel For”,但问题是我不知道文件有多少行
使用多个线程读取文件没有任何好处。该过程的那部分是 I/O 限制的,而不是 CPU 限制的。所以你最好从一个线程中读取整个文件。
然后,您需要将文件拆分为行。由于存在依赖性问题,这很难再次并行执行。第 N+1 行从第 N 行结束的地方开始。在单个线程中拆分成行是最简单的。
但是您可以在 I/O 和拆分成行之间运行管道。大块读取文件(比如一次几十 KB)。并将每个块传递到管道中以被处理成行。您可能需要为在任何时候允许在管道中放置多少数据设置一个上限。否则,如果文件的读取速度快于处理速度,您可能会耗尽内存。
因此,对于这个管道,您有一个读取文件的生产者和一个将文件内容拆分为行的消费者。
然后你可以运行另一个管道。在生产者端,您有上一步生成的行列表。这被推到了处理每一行的消费者的管道上。消费者将使用 parallel for 来做到这一点。
将解析拆分为例如 10.000 行的块可能是一种选择。我不知道 OmniThread 库,所以 <Do Parallel For on ARR> 部分你必须自己做,但代码的基本结构是这样的:
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>
请注意,代码假定 <Do Parallel For on ARR> 部分仅在数组中的所有条目都已处理后才继续。
您不需要知道使用 Parallel-For 的总行数,因为您可以使用阻塞集合来迭代。当您添加最后一行时,不要错过调用 CompleteAdding 。
请注意,与线程和队列管理相比,当每个单个任务只需要少量时间时,Parallel-For 的性能可能会严重下降。
您还可以考虑使用 BackgroundWorker 抽象并在每个 WorkItems 中安排多行。