1

遅延評価は、一度にメイン メモリに収まらない巨大なファイルを処理するようなものに大きな恩恵をもたらします。ただし、シーケンスにすぐに評価したい要素がいくつかあり、残りは遅延計算できるとします-それを指定する方法はありますか?

具体的な問題: (質問への回答に役立つ場合)

具体的には、一連の IEnumerables を複数のシーケンスの反復子として使用しています。これらのシーケンスは、BinaryReader ストリームを使用して開かれたファイルから読み取られたデータです (各シーケンスは、ファイルの 1 つからのデータの読み取りを担当します)。これらの MoveNext() は、特定の順序で呼び出されます。例えば。iter0それiter1から....などiter5iter3この順序は、別のシーケンスindex=で指定されます{0,1,5,3,....}。ただし、シーケンスは遅延しているため、当然、必要な場合にのみ評価が行われます。したがって、シーケンスの IEnumerables が移動しているときに、ファイルの読み取り (ディスク上のファイルから読み取る最初のシーケンスの場合) が発生します。これにより、不正なファイル アクセスが発生しています。1 つのプロセスによって読み取られているファイルが、(エラー メッセージに従って) 再度アクセスされます。

確かに、不正なファイル アクセスは他の理由による可能性があります。他の原因をデバッグするために最善を尽くした後、部分的な遅延評価を試してみる価値があるかもしれません。

4

2 に答える 2

3

Tomas のコメントには同意しますが、ファイル共有が適切に処理されている場合、これは必要ないはずですが、最初のN要素を積極的に評価する方法の 1 つを次に示します。

let cacheFirst n (items: seq<_>) =
  seq {
    use e = items.GetEnumerator()
    let i = ref 0
    yield! 
      [ 
        while !i < n && e.MoveNext() do
          yield e.Current
          incr i
      ]
    while e.MoveNext() do
      yield e.Current
  }

let items = Seq.initInfinite (fun i -> printfn "%d" i; i)

items
|> Seq.take 10
|> cacheFirst 5
|> Seq.take 3
|> Seq.toList

出力

0
1
2
3
4
val it : int list = [0; 1; 2]
于 2012-07-03T15:00:46.897 に答える
1

Seq.cacheダニエルの解決策は健全ですが、ほとんどの場合、別のオペレーターは必要ないと思います。

最初にシーケンスをキャッシュします:

let items = Seq.initInfinite (fun i -> printfn "%d" i; i) |> Seq.cache

最初から遅延アクセスが続く Eager 評価:

let eager = items |> Seq.take 5 |> Seq.toList
let cached = items |> Seq.take 3 |> Seq.toList

これにより、最初の 5 つの要素が 1 回 (実行中にeager) 評価されますが、それらは二次アクセスのためにキャッシュされます。

于 2012-07-04T01:45:01.897 に答える