【发布时间】:2011-02-25 22:09:09
【问题描述】:
我正在用 F# 编写一个解析器,它需要尽可能快(我希望在不到一分钟的时间内解析一个 100 MB 的文件)。像往常一样,它使用可变变量来存储下一个可用字符和下一个可用标记(即词法分析器和解析器都正确使用一个前瞻单元)。
我当前的部分实现对这些使用局部变量。由于闭包变量不能是可变的(有人知道原因吗?)我将它们声明为 ref:
let rec read file includepath =
let c = ref ' '
let k = ref NONE
let sb = new StringBuilder()
use stream = File.OpenText file
let readc() =
c := stream.Read() |> char
// etc
我认为这有一些开销(我知道,不多,但我在这里尝试最大速度),而且有点不雅。最明显的替代方法是创建一个解析器类对象并将可变变量作为其中的字段。有谁知道哪个可能更快?是否有任何共识被认为是更好/更惯用的风格?我还缺少其他选择吗?
【问题讨论】:
-
你有没有考虑过这个任务可能是 I/O 限制而不是计算限制?如果它是使用 refs 或 mutables 绑定的 I/O 并不重要,那么不同的是使用异步编程模型来加载您的数据。异步加载数据块并进行处理可以让您在处理文件的早期部分时加载数据。在进行这种异步编程时,F# 异步工作流程有很大帮助。
-
如果您在将文本转换为 AST 时只需要 1.7 Mb/秒,您可以使用您能找到的任何解析器。一些 OCaml 解析器组合器在解析大而不那么简单的语法时显示 >30Mb/s。 FParsec 很好,您可以使用它轻松更改语法。
-
Robert,根据我的经验,解析往往受 CPU 限制,但您提出了一个很好的观点,即如果可以使其受 I/O 限制,那么异步处理值得研究。
-
ssp,每秒 30 MB 解析复杂语法无疑是一个令人印象深刻的数字。我可能会研究 FParsec 使用的技术。谢谢!