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: 不,我的代码不正确:)检查我的帖子以获得答案。
我相信您通常错误地理解了代码 \xe2\x80\x93 中非惰性的原因,使用slip通常不应使代码急切。事实上,当我运行代码的稍微修改版本时,如下所示:
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}\nRun Code Online (Sandbox Code Playgroud)\nparse-file我得到的输出显示 Raku 延迟处理文件(请注意,它在需要将新值传递给 之前不会调用process-line):
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\nRun Code Online (Sandbox Code Playgroud)\n由于我没有您的其余代码,因此我不确定是什么触发了您正在观察的非惰性行为。一般来说,如果您的代码在您希望它是惰性的时正在急切地求值,那么方法.lazy和/或lazy语句前缀是很好的工具。
最后,关于您发布的代码的一些小注释与您的问题无关,但可能会有所帮助:
\nreturn语句(而且它实际上稍微慢/不惯用)。parse-filegather/的很大一部分力量take在于它们可以跨越功能边界。也就是说,您可以拥有一个位于不同行的parse-file函数take,而无需在 \xe2\x80\x93gather内包含语句,只需在块的范围内parse-lines调用即可。这感觉可能有助于解决您正在解决的问题,尽管在没有更多信息的情况下很难确定。parse-linesgather首先——我有很大的误解。我认为 产生的所有线条都必须像这样parse-file滑入地图中:block
@file-names.map( produce all lines here ).map( process all lines here );
Run Code Online (Sandbox Code Playgroud)
并且Slip是List跟踪所有元素的。这就是为什么我有严重的内存泄漏。
解决方案是在内部创建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)
| 归档时间: |
|
| 查看次数: |
112 次 |
| 最近记录: |