2013-08-20 17 views
5

我有一個代碼:爲什麼Seq.take F#中投的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. 

該代碼產生的內存不足。爲什麼?爲什麼在時間計算之後拋出異常(操作完成後)? AFAIK,單個序列元素僅根據需要進行計算?

+3

您在創建序列之前強制創建列表。刪除方括號應該有幫助 –

回答

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

從列表[1 .. 100000000]中創建一個序列,根據您的要求生成項目。這要求列表在內存中。該列表對於32位內存來說太大,因此OutOfMemoryException。你應該嘗試

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

是的,我完全忘記seq表達式中的列表。 – Sergey

+0

有趣的是,代碼在懶惰地嘗試獲取第一個100 000個元素之前熱切地創建列表。我猜編譯器必須非常聰明才能跳過列表的急切創建。 –

+0

@OnorioCatenacci這是因爲'fsi',它開始評估seq(甚至seq的第一項需要整個列表)。見@ GeneBelitski的回答。 –

6

除了揭示的核心問題原因,它可能是值得解決的問題的第二部分,爲什麼操作完成後拋出異常。

爲了得到理解這一點,這將有助於考慮到

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

不會跟任何異常,而看似無害

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

之後,將相同的以外,與原來的,儘管我們似乎不會嘗試實現序列的實現。

這是正確的,我們不這樣做,但FSI確實,試圖打印出幾首序列成員的值,比如下面一個小清單:

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

其引發的內存實例原始的龐大列表。