【问题标题】:Why does calling count on an Enumerator indefinitely hang?为什么对枚举器的调用计数无限期挂起?
【发布时间】:2020-05-11 03:13:44
【问题描述】:

我花了很长时间调试我的代码,试图找出为什么我的简单脚本没有错误消息/警告而挂起。

我正在循环遍历枚举器并根据该循环中的值执行特定任务。

下面的例子只是为了演示我是如何得出这个错误的(我知道这可以用更好的方式编码)

marketplaces = ["ebay","amazon","shopify"].cycle.each
complete = false

while(!complete)
  marketplace = marketplaces.next

  if marketplace == "ebay"
    // do abc
    completed = 1
  elsif marketplace == "amazon"
    // do def
    completed += 1
  elsif marketplace == "shopify"
    // do xyz
    completed += 1
  end

  // indefinetely hangs here
  if marketplaces.count == completed
    complete = true
  end
end

我的问题:

我现在明白了您不能在 Ruby 中对 Enumerator 类型调用 .count,但为什么它只是挂起,幕后发生了什么?


要重现,只需创建任何数组并将其转换为枚举器并在该对象上调用计数:

谢谢

【问题讨论】:

  • 您可以在Enumerator 上致电countEnumerators 是Enumerables,因此您可以计算它们。但是,你不能数到无穷大。
  • 你在数无限Enumerator的元素个数。你预计会发生什么?

标签: arrays ruby enums


【解决方案1】:

数组#cycle per the documentation:

为每个元素调用给定块 n 次,如果给定 nil,则永远调用。

由于您没有给出参数,它会无限期地调用该块,遍历数组中的所有值,然后再次从第一个值开始。

你可以通过执行看到这一点:

 [1,2].cycle { |i| p i }

为什么会挂起

count 调用不会挂起,它会为每个产生的值递增计数器。由于 Ruby 中的整数可以任意大,最终 count 调用将耗尽内存并失败,但这需要非常非常长的时间。

【讨论】:

    【解决方案2】:

    枚举器有两种确定元素个数的方法:

    • count 通过遍历集合来计算元素
    • size 计算大小

    如果无法计算大小,size 可能会返回 nil

    一般来说,size 要快得多:

    [1, 2].repeated_permutation(24).count  # takes some seconds
    #=> 16777216
    
    [1, 2].repeated_permutation(24).size   # returns immediately
    #=> 16777216
    

    它还可以很好地处理无限枚举:

    [1, 2].cycle.size
    #=> Infinity
    

    【讨论】:

      猜你喜欢
      • 2021-09-14
      • 1970-01-01
      • 2013-09-09
      • 2011-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多