[英]How to take lazy bytestring from zip archive without heap overflow
[英]How to slip gather-take in lazy manner into map?
我需要構建以下流程:
但是我不知道如何正確地注入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
}
這段代碼有效,但會瘋狂地泄漏內存。 我認為slip
會gather
- take
? 或者slip
沒有將Seq
項目標記為已消耗? 有沒有辦法滑動gather
- take
結果放入map
?
順便說一句:我的目的是將每個步驟與稍后的race
並行化 - 例如,我同時解析了 2 個文件,為 10 行處理器生成行。 一般來說,我試圖找出組成此類級聯流的最簡單方法。 我已經嘗試使用 Channels 來連接每個處理步驟,但它們沒有內置的回推。 如果您有任何其他此類流程的模式,那么歡迎發表評論。
編輯 1:
我認為我的代碼是正確的,內存泄漏不是由錯誤的邏輯引起的,而是由 Slip 類中的錯誤引起的。 我創建了當前打開的問題https://github.com/rakudo/rakudo/issues/5138 。 問題解決后,我會發布更新。
編輯 2:不,我的代碼不正確 :) 檢查我的帖子以獲得答案。
我相信您錯誤地理解了代碼中非懶惰的原因——一般來說,使用slip
通常不會使代碼變得急切。 而且,事實上,當我運行您的代碼的略微修改版本時,如下所示:
sub MAIN () {
my @file-names = "tmp-file000".."tmp-file009";
spurt $_, ('a'..'z').join("\n") for @file-names;
my $parsed = @file-names.map( { slip parse-file( $_ ) } );
say "Reached line $?LINE";
$parsed.map( { process-line( $_ ) } );
}
sub parse-file ( $file-name ) {
say "processing $file-name...";
gather for $file-name.IO.lines -> $line {
take $line if $line ~~ /a/; # dummy example logic
}
}
sub process-line ( $line ) {
say $line; # dummy example logic
}
我得到的輸出顯示 Raku 延遲處理文件(請注意,在需要將新值傳遞給process-line
之前,它不會調用parse-file
):
Reached 8
processing tmp-file000...
a
processing tmp-file001...
a
processing tmp-file002...
a
processing tmp-file003...
a
processing tmp-file004...
a
processing tmp-file005...
a
processing tmp-file006...
a
processing tmp-file007...
a
processing tmp-file008...
a
processing tmp-file009...
a
由於我沒有您的其余代碼,因此我不確定是什么觸發了您觀察到的非惰性行為。 一般來說,如果您的代碼在您希望它惰性化時正在急切求值,那么.lazy
方法和/或lazy
語句前綴是很好的工具。
最后,關於您發布的代碼的一些小注釋與您的問題無關,但可能會有所幫助:
parse-file
中的return
語句不是必需的(而且它實際上稍微慢一些/非慣用)。gather
/ take
的很大一部分力量在於它們可以跨越功能邊界。 也就是說,您可以擁有一個take
不同行的parse-file
函數,而無需在parse-lines
內包含gather
語句——您只需要在gather
塊的范圍內調用parse-lines
。 感覺這可能有助於解決您正在處理的問題,盡管在沒有更多信息的情況下很難確定。 首先 - 我有很大的誤解。 我認為parse-file
生成的所有行都必須像這樣滑入 map block
:
@file-names.map( produce all lines here ).map( process all lines here );
而Slip
是一個跟蹤所有元素的List
。 這就是為什么我有很大的內存泄漏。
解決方案是在map
內創建gather
- take
sequence 但在map
外使用它:
@file-names.map( { parse-file( $_ ) } ).flat.map( { process-line( $_ ) } );
所以現在是:
@file-names.map( construct sequence here ).(get items from sequence here).map( process all lines here );
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.