【问题标题】:Why Seq.take in F# throw System.OutOfMemoryException为什么 F# 中的 Seq.take 会抛出 System.OutOfMemoryException
【发布时间】:2013-08-20 12:18:45
【问题描述】:

我有一个代码:

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,仅根据需要计算单个序列元素?

【问题讨论】:

  • 您在创建序列之前强制创建一个列表。删除方括号应该会有所帮助

标签: memory-management f# sequence


【解决方案1】:
seq {for i in [1 .. 100000000] -> i} |> Seq.take 100000

从列表[1 .. 100000000] 中创建一个序列,该序列将根据您的要求生成项目。这要求列表在内存中。该列表对于 32 位内存来说太大了,因此是 OutOfMemoryException。你应该试试

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

【讨论】:

  • 是的,我完全忘记了 seq 表达式中的列表。
  • 在懒惰地尝试获取前 100 000 个元素之前,代码急切地创建列表有点有趣。我想编译器必须非常聪明才能跳过急切地创建列表。
  • @OnorioCatenacci 是因为fsi,它开始评估seq(甚至seq的第一项需要整个列表)。请参阅@GeneBelitski 的回答。
【解决方案2】:

除了揭示核心问题原因之外,可能值得解决问题的第二部分,即为什么在操作完成后抛出异常。

为了理解这一点,考虑到这一点会有所帮助

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; ...]

它启动原始庞大列表的内存实例化。

【讨论】:

    猜你喜欢
    • 2010-11-17
    • 1970-01-01
    • 2019-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    相关资源
    最近更新 更多