2013-08-20 9 views
5

mam kod:Dlaczego Seq.take w F # rzutów System.OutOfMemoryException

seq {for i in [1 .. 100000000] -> i} |> Seq.take 100000;; 
Real: 00:00:00.000, CPU: 00:00:00.000, GC gen0: 0, gen1: 0, gen2: 0 
val it : seq<int> = 
    Error: Exception of type 'System.OutOfMemoryException' was thrown. 

Ten kod wyników w pamięci. Czemu? I dlaczego wyjątek został zgłoszony po obliczeniu czasu (po zakończeniu operacji)? AFAIK, poszczególne elementy sekwencji są obliczane tylko w razie potrzeby?

+3

wymuszenie utworzenia listy przed wykonaniem sekwencji. usunięcie nawiasów kwadratowych powinno pomóc –

Odpowiedz

8
seq {for i in [1 .. 100000000] -> i} |> Seq.take 100000 

tworzy sekwencję, która będzie generować przedmiotów, jak poprosić o nich z listy [1 .. 100000000]. To wymaga, aby lista znajdowała się w pamięci. Lista jest zbyt duża dla pamięci 32-bitowej, stąd OutOfMemoryException. Należy starać

seq {for i in 1 .. 100000000 -> i} |> Seq.take 100000 
+0

Tak, całkowicie zapominam o liście w wyrażeniu seq. – Sergey

+0

To jest trochę interesujące, że kod chętnie tworzy listę, zanim leniwie próbuje zdobyć pierwsze 100 000 elementów. Domyślam się, że kompilator musiałby być wyjątkowo inteligentny, aby pominąć szybkie tworzenie listy. –

+0

@OnorioCatenacci To z powodu 'fsi', które zaczyna oceniać seq (a nawet pierwszy element seq wymaga całej listy). Zobacz odpowiedź @ GeneBelitskiego. –

6

oprócz odsłaniając rdzeń problemu powód może warto zajęcie się drugą część pytania, dlaczego jest wyjątek po zakończeniu operacji.

Dla uzyskania tego zrozumieć, że to pomoże, uznając, że

let mySeq = seq {for i in [1 .. 100000000] -> i} |> Seq.take 100000;; 

nie nastąpi żadnych wyjątków, a pozornie nieszkodliwe

seq {for i in [1 .. 100000000] -> i};; 

nastąpi tego samego wyjątku, jak w oryginale, chociaż wydaje się, że i tak nie próbujemy zmaterializować sekwencji.

To prawda, że ​​nie, ale FSI robi, próbując wydrukować wartości kilku pierwszych elementów sekwencji, jak dla mniejszych poniższej listy:

seq {for i in [1 .. 100] -> i};; 
val it : seq<int> = seq [1; 2; 3; 4; ...] 

który inicjuje instancji w pamięci o oryginalna obszerna lista.

Powiązane problemy