如何使用 FParsec 在 F# 中解析一个非常大的文件

How to parse a very large file in F# using FParsec

我正在尝试使用 FParsec 解析一个非常大的文件。该文件的大小为 61GB,太大而无法保存在 RAM 中,因此如果可能的话,我想生成一个结果序列(即 seq<'Result>),而不是一个列表。这可以用 FParsec 完成吗? (我已经想出了一个实际上可以做到这一点的偷工减料的实现,但由于 CharStream.Seek 的 O(n) 性能,它在实践中效果不佳。)

该文件是面向行的(每行一条记录),这在理论上应该可以分批解析,比如说,一次解析 1000 条记录。 FParsec“Tips and tricks”部分说:

If you’re dealing with large input files or very slow parsers, it might also be worth trying to parse multiple sections within a single file in parallel. For this to be efficient there must be a fast way to find the start and end points of such sections. For example, if you are parsing a large serialized data structure, the format might allow you to easily skip over segments within the file, so that you can chop up the input into multiple independent parts that can be parsed in parallel. Another example could be a programming languages whose grammar makes it easy to skip over a complete class or function definition, e.g. by finding the closing brace or by interpreting the indentation. In this case it might be worth not to parse the definitions directly when they are encountered, but instead to skip over them, push their text content into a queue and then to process that queue in parallel.

这对我来说听起来很完美:我想将每批记录预解析到一个队列中,然后再并行解析它们。但是,我不知道如何使用 FParsec API 来完成此操作。如何在不耗尽所有 RAM 的情况下创建这样的队列?

FWIW,我要解析的文件是 here,如果有人想和我一起试一试的话。 :)

我想到的 "obvious" 是使用 File.ReadLines 之类的方法预处理文件,然后一次解析一行。

如果这不起作用(您的 PDF 看起来像一条记录只有几行那么长),那么您可以使用普通的 FileStream 读取来创建一系列记录或 1000 条记录或类似的记录。这样就不需要知道记录的详细信息了,不过如果能至少给记录划个界就好了。

无论哪种方式,您最终都会得到解析器可以读取的惰性序列。