簡體   English   中英

如何以懶惰的方式將 gather-take 滑入地圖?

[英]How to slip gather-take in lazy manner into map?

我需要構建以下流程:

  • 接受文件名列表
  • 從這些文件中提取多行
  • 處理那些行

但是我不知道如何正確地注入gather - takemap中:

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
}

這段代碼有效,但會瘋狂地泄漏內存。 我認為slipgather - 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語句前綴是很好的工具。


最后,關於您發布的代碼的一些小注釋與您的問題無關,但可能會有所幫助:

  1. 所有 Raku 函數都返回它們的最終表達式,因此parse-file中的return語句不是必需的(而且它實際上稍微慢一些/非慣用)。
  2. 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM