VZ.*_*VZ. 6 parallel-processing grammar raku
使用我的语法使用简单的语法解析数百个文件
for @files -> $file {
my $input = $file.IO.slurp;
my $output = parse-and-convert($input);
$out-dir.IO.add($file ~ '.out').spurt: $output;
}
Run Code Online (Sandbox Code Playgroud)
循环相对较慢,在我的机器上大约需要 20 秒,因此我决定通过这样做来加快速度:
my @promises;
for @files -> $file {
my $input = $file.IO.slurp;
@promises.append: start parse-and-convert($input);
}
for await @promises -> $output {
$out-dir.IO.add($file ~ '.out').spurt: $output;
}
Run Code Online (Sandbox Code Playgroud)
这有效(至少在我的真实代码中,即对这个说明性示例中的任何拼写错误取模),但加速比我希望的要少得多:现在需要大约 11 秒,即我只获得了两倍。当然,这是值得重视的,但看起来存在很多争用,因为该程序使用的 CPU 数量少于 6 个(在有 16 个 CPU 的系统上),并且有相当多的开销(因为我没有得到6 加速都没有)。
我已经确认(通过插入一些say now - INIT.now)几乎所有运行时间都真正花费在内部await,如预期的那样,但我不知道如何进一步调试/分析它。我在 Linux 下执行此操作,因此我可以使用 perf,但我不确定它在 Raku 级别对我有何帮助。
有没有一些简单的方法可以提高这里的并行度?
编辑:为了说清楚,我可以忍受 20 秒(好吧,现在是 30 秒,因为我添加了更多东西)运行时间,我真的很好奇并行度是否可以在这里以某种方式提高,而不需要重写语法(除非有一些非常具体的东西,例如使用动态变量,在使用多线程时应该避免)。
一个问题,一个建议:
您的语法会解析整个文档,还是仅解析这些文档的一部分(章节、段落、行等)?
如果您的语法仅在段落或行级别进行解析,那么您可能会花费大量时间slurp来加载文件。Raku 例程的优点lines是它的读取速度较慢。要复制并替换slurp第二行代码,您可以尝试以下操作:
my $input = $file.IO.lines.join("\n");
Run Code Online (Sandbox Code Playgroud)
否则,如果您的语法在段落级别进行解析,则您可以使用 Raku 中数组的强大功能(请注意下面的分配 to@input而不是$input)。您还可以>>(超级)处理数组元素以提供加速,因为正如文档所说,“...所有超级运算符都是并行性的候选者...”:
my @input = $file.IO.split("\n\n");
Run Code Online (Sandbox Code Playgroud)
如果您需要进行复杂的段落(预)解析,请查看Text::Paragraph@Codesections 的_“lowbar”模块的子模块:
https://github.com/codesections/_/blob/main/lib/Text/Paragraphs/README.md
无论如何,加速的最佳机会似乎是减少“阻抗不匹配”,即确保提供给 Grammar 的块大小与 Grammar 期望的大小匹配(而不是创建文件读取瓶颈)在执行语法之前)。
HTH。
| 归档时间: |
|
| 查看次数: |
238 次 |
| 最近记录: |