如何以懒惰的方式将采集滑入地图中?

Paw*_*bkr 7 memory-leaks lazy-evaluation rakudo lazy-sequences raku

我需要构建以下流程:

  • 接受文件名列表
  • 从这些文件中提取多行
  • 处理这些行

但是我不知道如何正确地将gather-take注入map

sub MAIN ( *@file-names ) {

    @file-names.map( { slip parse-file( $_ ) } ).map( { process-line( $_ ) } );
}

sub parse-file ( $file-name ) {
    return gather for $file-name.IO.lines -> $line {
        take $line if $line ~~ /a/; # dummy example logic
    }
}

sub process-line ( $line ) {
    say $line;  # dummy example logic
}
Run Code Online (Sandbox Code Playgroud)

这段代码可以工作,但是会疯狂地泄漏内存。我认为slip让人gather-take渴望?或者slip不将Seq物品标记为已消耗?有没有办法以懒惰的方式gather滑入take结果?map

顺便说一句:我的目的是并行化每个步骤race- 例如,我同时解析 2 个文件,为 10 行处理器生成行。一般来说,我试图找出组成此类级联流的最简单方法。我尝试过使用通道来连接每个处理步骤,但它们没有内置的推回功能。如果您对此类流程有任何其他模式,那么非常欢迎发表评论。

编辑1:

我认为我的代码是正确的,内存泄漏不是由错误的逻辑引起的,而是由 Slip 类中的错误引起的。我创建了当前开放的问题https://github.com/rakudo/rakudo/issues/5138 。解决后我会发布更新。

编辑2: 不,我的代码不正确:)检查我的帖子以获得答案。

cod*_*ons 6

我相信您通常错误地理解了代码 \xe2\x80\x93 中非惰性的原因,使用slip通常不应使代码急切。事实上,当我运行代码的稍微修改版本时,如下所示:

\n
sub MAIN () {\n    my @file-names = "tmp-file000".."tmp-file009";\n    spurt $_, (\'a\'..\'z\').join("\\n") for @file-names;\n\n    my $parsed = @file-names.map( { slip parse-file( $_ ) } );\n    say "Reached line $?LINE";\n\n    $parsed.map( { process-line( $_ ) } );\n}\n\nsub parse-file ( $file-name ) {\n    say "processing $file-name...";\n    gather for $file-name.IO.lines -> $line {\n        take $line if $line ~~ /a/; # dummy example logic\n    }\n}\n\nsub process-line ( $line ) {\n    say $line;  # dummy example logic\n}\n
Run Code Online (Sandbox Code Playgroud)\n

parse-file我得到的输出显示 Raku 延迟处理文件(请注意,它在需要将新值传递给 之前不会调用process-line):

\n
Reached 8\nprocessing tmp-file000...\na\nprocessing tmp-file001...\na\nprocessing tmp-file002...\na\nprocessing tmp-file003...\na\nprocessing tmp-file004...\na\nprocessing tmp-file005...\na\nprocessing tmp-file006...\na\nprocessing tmp-file007...\na\nprocessing tmp-file008...\na\nprocessing tmp-file009...\na\n
Run Code Online (Sandbox Code Playgroud)\n

由于我没有您的其余代码,因此我不确定是什么触发了您正在观察的非惰性行为。一般来说,如果您的代码在您希望它是惰性的时正在急切地求值,那么方法.lazy和/或lazy语句前缀是很好的工具。

\n
\n

最后,关于您发布的代码的一些小注释与您的问题无关,但可能会有所帮助:

\n
    \n
  1. 所有 Raku 函数都会返回其最终表达式,因此不需要 中的return语句(而且它实际上稍微慢/不惯用)。parse-file
  2. \n
  3. gather/的很大一部分力量take在于它们可以跨越功能边界。也就是说,您可以拥有一个位于不同行的parse-file函数take,而无需在 \xe2\x80\x93gather内包含语句,只需在块的范围内parse-lines调用即可。这感觉可能有助于解决您正在解决的问题,尽管在没有更多信息的情况下很难确定。parse-linesgather
  4. \n
\n


Paw*_*bkr 2

首先——我有很大的误解。我认为 产生的所有线条都必须像这样parse-file滑入地图中:block

@file-names.map( produce all lines here ).map( process all lines here );
Run Code Online (Sandbox Code Playgroud)

并且SlipList跟踪所有元素的。这就是为什么我有严重的内存泄漏。

解决方案是在内部创建gather-take序列map但在外部使用它map

@file-names.map( produce all lines here ).map( process all lines here );
Run Code Online (Sandbox Code Playgroud)

所以现在是:

@file-names.map( construct sequence here ).(get items from sequence here).map( process all lines here );
Run Code Online (Sandbox Code Playgroud)