证明在循环中使用范围运算符不会使用额外的内存

2023-11-27

当前的文档范围运算符..声明它不会消耗内存计数循环:

...范围运算符对于编写很有用foreach (1..10)循环以及对数组进行切片操作。在当前的实现中,没有创建临时数组当范围运算符用作 foreach 循环中的表达式时,但是当您编写如下内容时,旧版本的 Perl 可能会消耗大量内存:

    1.   for (1 .. 1_000_000) {
    2.       # code
    3.   }

由于前面提到的早期实现for (MIN .. MAX),我仍然遇到对使用计数循环持谨慎态度的专家,因为他们认为它相当于:

my @temp_array = (MIN .. MAX);       # Needlessly using up memory
for (@temp_array) {

与逻辑和内存效率更高的相比:

for ($_ = MIN; $_ <= MAX; $_++) {    # Logical counting from MIN to MAX

问题:

  • 有没有一种方法可以证明计数循环不会浪费内存?

  • 有谁知道 Perl 的哪些版本存在内存问题以及何时修复?

我能够向自己证明,使用下面的一行语句计数循环不会浪费内存,如果它实际上创建了一个临时数组,那么它肯定会导致我的系统崩溃。然而,如果能有关于这个主题的更多确凿信息就好了,这样我们就可以结束这个老太太的故事了。

$ perl -e 'for (1 .. 1_000_000_000_000_000) { print "$_\n"; last if $_ == 5 }'
1
2
3
4
5

Solution

以下三个答案都部分解释了这个问题:

  1. ikegami's answer彻底分解了不同类型的循环,并演示了计数循环在前端和后端的差异。 &星星;
  2. friedo's answer显示如何使用top来监控内存使用情况。
  3. Borodin's answer addresses the second part of my query about when this no longer became an issue:
    • perlop v5.4_68(1998 年 6 月 23 日发布)警告使用了临时数组。
    • perlop v5.4_69(1998 年 6 月 29 日发布)声明不再使用临时数组。
    • perldelta v5.4_71(1998 年 7 月 9 日发布)指出计数循环已优化。

我可能会在某个时候进行一些特定的版本测试,但考虑到这显然是一个 16 年前的问题,我相信中的警告perlop可以休息了。


首先,这是不同类型的列表for循环和可以应用的优化。所有这些都存在于 Perl 从 5.6 到 5.20(现在)的每个版本中,我相信它是全面的。

  • for (EXPR; EXPR; EXPR)
    ⇒“C 风格的 for 循环”,一个增强的 while 循环。
  • for (EXPRX..EXPRY)
    ⇒ 将一个范围而不是其他内容优化为计数循环。
  • for (@ARRAY)
    ⇒ 直接访问数组而不是展平其他任何东西。
  • for (reverse LIST)
    ⇒ 上述优化均不适用,但列表是反向遍历的,而不是反向的。
  • for (LIST)
    ⇒ 在通用的 foreach 循环中,LIST表达式在循环开始之前计算。

When CONSTX..CONSTY被展平(即除for (CONSTX..CONSTY)),它在编译时而不是运行时被展平。


黑盒证明

基线内存使用情况:

$ perl -e'system(ps, ho, rss, 0+$$);'
 1540         # 1.5 MiB

一般情况趋于平缓。

$ perl -e'$y=2_000_000; for ((),1..$y) { system(ps, ho, rss, 0+$$); last }'
80208         # 78 MiB

或者更糟。 (除了正常的堆栈使用之外,它还在编译时展平为数组。)

$ perl -e'for ((),1..2_000_000) { system(ps, ho, rss, 0+$$); last }'
143224        # 140 MiB

for (CONST..CONST)不平坦。

$ perl -e'for (1..2_000_000) { system(ps, ho, rss, 0+$$); last }'
 1540         # 1.5 MiB

实际上,for (EXPR..EXPR)一般不会变平。

$ perl -e'$y=2_000_000; for (1..$y) { system(ps, ho, rss, 0+$$); last }'
 1540         # 1.5 MiB

即使没有工具,您也可以看出编译时间的差异。

$ time perl -c -e'1 for 1..2_000_000'
-e syntax OK

real    0m0.010s
user    0m0.004s
sys     0m0.000s

$ time perl -c -e'1 for (),1..2_000_000'
-e syntax OK

real    0m1.197s
user    0m0.952s
sys     0m0.232s

白盒证明

未优化的情况使用范围运算符l它的上下文。内存中的完整列表。

$ perl -MO=Concise,-exec -e'$y=1_000_000; 1 for (),1..$y;'
...
8  <|> range(other->9)[t3] lK/1                      <-- Range operator
9      <#> gvsv[*y] s
a      <1> flop lKM
           goto b
i  <$> const[IV 1] s
j  <1> flip[t4] lK/LINENUM
b  <#> gv[*_] s
c  <{> enteriter(next->d last->g redo->d) lK/8       <-- No S
...

这是编译时展平的范围的样子:

$ perl -MO=Concise,-exec -e'1 for (),1..1_000_000;'
...
4  <$> const[AV ] s                                  <-- Constant array
5  <1> rv2av lKPM/1
6  <#> gv[*_] s
7  <{> enteriter(next->8 last->b redo->8) lK/8       <-- No S
...

你可以看到for (CONST..CONST)创建一个enteriter带有“S”标志。在enteriter,“S”标志表示它是一个计数循环。

$ perl -MO=Concise,-exec -e'1 for 1..1_000_000;'
...
4  <$> const[IV 1] s
5  <$> const[IV 1000000] s
6  <#> gv[*_] s
7  <{> enteriter(next->8 last->b redo->8) lKS/8       <-- S
...

同样适用于for (EXPR..EXPR)一般来说。

$ perl -MO=Concise,-exec -e'$y=1_000_000; 1 for 1..$y;'
...
8  <$> const[IV 1] s
9  <#> gvsv[*y] s
a  <#> gv[*_] s
b  <{> enteriter(next->c last->f redo->c) lKS/8       <-- S
...

Even for (@a)没有被压扁!

$ perl -MO=Concise,-exec -e'1 for @a;'
...
4  <#> gv[*a] s
5  <1> rv2av[t2] sKRM/1
6  <#> gv[*_] s
7  <{> enteriter(next->8 last->b redo->8) lKS/8       <-- S
...

再检查一遍

$ perl -MO=Concise,-exec -e'1 for (),@a;'
...
4  <#> gv[*a] s
5  <1> rv2av[t2] lKM/1
6  <#> gv[*_] s
7  <{> enteriter(next->8 last->b redo->8) lK/8        <-- No S
...

查找“S”标志的代码将确认所有这些。

  • pp_enteriter (PL_op->op_flags & OPf_STACKED检查“S”)
  • pp_iter.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

证明在循环中使用范围运算符不会使用额外的内存 的相关文章

  • 根据同一 select 语句中先前计算的行(或列)计算新行(或列)

    我正在尝试根据年度销售增长预期来计算年度预期销售量 在一张表中 我有实际销量 create table Sales ProductId int Year int GrowthRate float insert into Sales valu
  • 从函数返回哈希值的最佳 Perl 实践是什么?

    我正在考虑将哈希引用传递给函数或从函数返回数据的最佳实践 一方面 仅将输入值传递给函数并仅返回输出变量似乎很直观 然而 在 Perl 中传递哈希值只能通过引用来完成 因此有点混乱 而且似乎更有可能犯错误 另一种方法是在输入变量中传递引用 但
  • 你将如何在 Haskell 中(重新)实现迭代?

    iterate a gt a gt a gt a 你可能知道 iterate是一个接受函数和起始值的函数 然后它将函数应用于起始值 然后将相同的函数应用于最后的结果 依此类推 Prelude gt take 5 iterate 2 2 2
  • 如何在Shiny中动态生成的条件面板中格式化条件?

    我正在尝试使用 for 循环在 Shiny 中创建小部件 每个块包含 label 复选框 选择选择器 两个数字输入 我想根据复选框的值和选择选择器的值来设置显示或隐藏两个数字输入的条件 在我创建的 for 循环中 我为每个小部件变量添加了一
  • C# While 循环与 For 循环?

    在 C 中 一个问题已经困扰我一段时间了 它的 While 和 For 循环之间的实际主要区别是什么 它只是纯粹的可读性吗 在 for 循环中本质上可以做的所有事情都可以在 while 循环中完成 只是在不同的地方 举这些例子 int nu
  • 在 Perl 中检测全局破坏

    我想检测我的物体是否被DESTROY作为全局破坏的一部分 并打印出警告 因为这显然是一个错误并导致数据丢失 显而易见的方法似乎是 sub DESTROY my self shift if i am in global destruction
  • 如何比较 JavaScript 表格中的单元格并测试是否相等? indexOf 是如何工作的?

    我在 HTML 代码中创建了一个表格 它有 9 列和 13 行 它被 JavaScript 循环完全填满 该循环用几个数组中的人名填充它 但是 我想添加一个验证步骤 确保一行中没有两个单元格具有相同的值 并且每个单元格的值不会在其正下方的单
  • for 循环与 cor.test 在许多类别上

    我正在尝试在 R 中编写一个循环 它将循环遍历 3 个不同的物种 以计算两个连续变量 Redness 和 VarNormAbund 之间的相关性 我的循环正在运行 但 3 个物种中每一个的输出都是相同的 这让我认为循环卡在第一个物种上 co
  • for循环中更新JLabel的问题

    我的程序的想法是从之前在其他 JFrame 中保存的列表中选择一个名称 我想在标签中一个接一个地打印所有名称 它们之间有很小的延迟 然后停在其中一个名称上 问题是lbl setText String 如果有多个则不起作用setText co
  • 如何循环遍历字典列表并打印特定键的值?

    我是 Python 新手 有一个问题 我知道这是一个非常简单的问题 运行Python 3 4 我有一个需要迭代并提取特定信息的列表 以下是列表 称为部分 的示例 已截断 数千个项目 state DEAD id phwl type name
  • 计算按前两列中的索引分组的 numpy 数组条目的第 N 列的总和?

    我想循环以下内容check matrix以这样的方式 代码可以识别第一个和第二个元素是否是1 and 1 or 1 and 2ETC 然后对于每个单独的类对 即1 1 or 1 2 or 2 2 代码应将最后一个元素 在本例中索引为 8 乘
  • Perl:模板工具包的替代品

    我使用模板工具包来扩展现有的领域特定语言 verilog 已经超过 3 年了 虽然总的来说我对此感到满意 但主要的刺激性是 当出现语法 undef 错误时 错误消息不包含用于调试错误的正确行号信息 例如我会收到一条消息 指示 0 未定义 因
  • Java 相当于 Perl 的 s/// 运算符?

    我有一些代码正在从 Perl 转换为 Java 它大量使用了正则表达式 包括s 操作员 我已经使用 Perl 很长时间了 但仍然习惯 Java 的做事方式 特别是 字符串似乎更难使用 有谁知道或有一个完全实现的Java函数s 这样它就可以处
  • matlab 中的 for 或 while 循环

    我刚刚开始在编程课的 matlab 中使用 for 循环 基本的东西对我来说很好 但是我被要求 使用循环创建一个 3 x 5 矩阵 其中每个元素的值是其行号其列号除以行号和列号之和的幂 例如元素 2 3 的值为 2 3 2 3 1 6 那么
  • 当 sleep() 不能与闹钟配合使用时,我还能做什么“睡眠”?

    有许多文档说 您应该避免使用带有警报的睡眠 因为许多系统使用警报来实现睡眠 事实上 我正在遭受这个问题的困扰 那么 当 sleep 无法与闹钟配合使用时 有人可以帮助我 我还能做什么 睡眠 吗 我已经尝试过 Time HiRes 模块的 u
  • Bash 目录上的 For 循环

    快速背景 ls src file1 file2 dir1 dir2 dir3 Script bin bash for i in src do if d i then echo i fi done Output src dir1 src di
  • Perl 三元条件运算符内部赋值问题

    我的程序中的这段 Perl 代码给出了错误的结果 condition a 2 a 3 print a 无论价值如何 condition就是 输出总是3 为什么呢 Perl 中对此进行了解释文档 http perldoc perl org p
  • 导入 .pl 文件

    我想知道如何将 Perl 文件导入到脚本中 我尝试了 use require 和 do 但似乎没有什么对我有用 这就是我用 require 做到的 usr bin perl require equations print x1 n 是否可以
  • 在 Perl 中,如何制作数组的深层复制? [复制]

    这个问题在这里已经有答案了 可能的重复 在 Perl 中制作数据结构深层复制的最佳方法是什么 https stackoverflow com questions 388187 whats the best way to make a dee
  • 在Java中将*s打印为三角形?

    我在 Java 课程中的作业是制作 3 个三角形 一份左对齐 一份右对齐 一份居中 我必须为什么类型的三角形制作一个菜单 然后输入需要多少行 三角形必须看起来像这样 到目前为止 我能够完成左对齐的三角形 但我似乎无法获得其他两个 我尝试用谷

随机推荐

  • cURL:操作在 0 毫秒后超时

    cURL 给我错误 Operation timed out after 0 milliseconds with 0 out of 0 bytes received 特别是 0毫秒 部分很可疑 我的初始化代码 curl curl init r
  • 如何将参数(action.payload)传递给 ngrx/effects 中的服务?

    我是 ngrx 6 的新手 效果将侦听操作 LOAD COURSE DETAILS 并应使用 course id action payload 调用服务 但我收到错误 Action 类型中缺少属性 toFixed 但是 如果我执行 cons
  • 安装 ASP.NET 和 Web Tools 2015 后,Visual Studio 出现错误“对象引用未设置为对象的实例”

    安装 ASP NET 和 Web Tools 2015 RC1 更新 1 后 打开 ASP NET MVC 4 项目时出现以下错误 cshtml files 未将对象引用设置为对象的实例 即使我启动一个新的 ASP NET MVC 4 项目
  • Eclipse 中的 Egit 导入显示运行时错误

    我尝试制作一个非常简单的 hello world 在 Eclipse 中使用 Egit 导入 我没有发现任何证据表明该软件无法正常工作 在谷歌中没有发现错误 所以看起来我犯了一些我不知道的错误 我按照此处定义的步骤进行操作 http cra
  • 如何对字典中的所有值求和?

    假设我有一个字典 其中的键映射到整数 例如 d key1 1 key2 14 key3 47 是否有一种语法上简约的方法来返回值的总和d i e 62在这种情况下 正如您所期望的 sum d values
  • 将 UUID 与 LINQ to Entities 中的字符串进行比较会引发错误 [重复]

    这个问题在这里已经有答案了 编辑 这不是重复的 建议的 SO 链接希望我打电话ToString 但我正在运行 COUNT 并试图做一个比比较更大的事情ToString 不是正确答案 我正在尝试使用以下方式填充变量IF快捷方式 但当我运行它时
  • SSRS:根据参数值有条件隐藏列 - CSV 导出忽略

    我在 SSRS 2008 中有一个简单的基于表格的报告 有 10 列 每列都有一个相应的参数来确定是否应显示该列 我通过设置在设计模式下右键单击列标题时获得的 列可见性 选项来实现此目的 就我而言 我选择 根据表达式显示或隐藏 将表达式设置
  • Pod Init 没有创建 xcworkspace?

    我启动了一台新 Mac 运行 sudo gem install cocoapods 完成 Pod 初始化 Pod 文件已创建 但没有 xcworkspace 文件 使用 Xcode 9 3 任何帮助表示赞赏 尝试过 卸载 cocoapods
  • 使用 R 中的工具提示绘制县级数据

    我在 www betydb org 上看到了美国县级的交互式分区统计图 我想使用 R 重现类似的地图 我只想要地图和工具提示 不是不同缩放级别的所有图块 或者切换地图的能力 该地图当前创建于ruby 弹出窗口 左下角 查询 MySQL 数据
  • 如何自动更新 MS-Access 2007 应用程序

    我有一个与 MySql 服务器通信的前端 Access 2007 应用程序 我想要一个功能 用户计算机上的应用程序可以检测到网络上有新版本 这并不困难 并将最新版本下载到本地驱动器并启动它 有谁有任何知识或经验如何做到这一点 Thanks
  • 如何在xampp中启用curl? [复制]

    这个问题在这里已经有答案了 如何在xampp中启用curl 我的 PHP twitter 应用程序需要curl 函数 但在 XAMPP 中并未启用它 如何启用它 我没有找到这样做的选择 您必须修改 xampp 文件夹中的 php ini 文
  • 如何在 Verilog 中将长语句分成行

    例如 我有一个很长的声明 display input data x output data x result x input data output data result 如何在 Verilog 中将其变成单语句和多行 您需要分解引用的字
  • 启动一个即使在 IE 中也能正常运行的文件下载?

    我正在寻找有关从 Javascript 启动文件下载的最佳方法的更多想法 启动下载的最佳方式 有很多好的想法 可以总结一下 在 iframe 上设置 src 使用 window location replace 使用带有元刷新标题的页面 使
  • Codeigniter URL 在没有 index.php 的情况下无法工作

    我刚刚建立了一个新网站http www reviewongadgets com 但是URL渲染有问题 当我输入如下 URL 时 它不起作用并给出页面未找到错误http www reviewongadgets com latest mobil
  • C 结构体成员的默认值

    是否可以为某些结构成员设置默认值 我尝试了以下方法 但是会导致语法错误 typedef struct int flag 3 MyStruct Errors gcc o testIt test c test c 7 error expecte
  • 在seaborn中使用Unicode文本

    我想在 Seaborn 中使用 Unicode 文本 Python 2 7 我可以使用 Unicode 文本作为 matplotlib 的图块 例如 import matplotlib pyplot as plt from matplotl
  • 告诉 Puppeteer 打开 Chrome 选项卡而不是窗口

    如果我打开了现有的 Google Chrome 窗口 我想告诉 puppeteer 打开一个新选项卡而不是打开一个新窗口 有没有办法做到这一点 是否有一些选项或标志我可以传递给木偶师来完成此任务 I have const puppeteer
  • 标准表单身份验证 Java servlet

    使用 Java Servlet 进行表单身份验证的标准方法是什么 从现在开始 我自己使用简单的 POST HTML 表单实现了这一点 根据数据库检查发送的参数 如果存在 将 User 对象保存到 HttpSession 中 检查每个 Ser
  • 解析 ANTLR 中的字符串插值

    我正在开发一个用于内部目的的简单字符串操作 DSL 并且我希望该语言能够支持 Ruby 中使用的字符串插值 例如 name Bob msg Hello name print msg prints Hello Bob 我正在尝试在 ANTLR
  • 证明在循环中使用范围运算符不会使用额外的内存

    当前的文档范围运算符 声明它不会消耗内存计数循环 范围运算符对于编写很有用foreach 1 10 循环以及对数组进行切片操作 在当前的实现中 没有创建临时数组当范围运算符用作 foreach 循环中的表达式时 但是当您编写如下内容时 旧版