AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 79599365
Accepted
Ed Staub
Ed Staub
Asked: 2025-04-30 08:34:25 +0800 CST2025-04-30 08:34:25 +0800 CST 2025-04-30 08:34:25 +0800 CST

V8 是否根据闭包值优化内部函数?

  • 772

例如:

function makeFunc(a,b,c,d,e) {
    return () => {
        if (a) { /* do something expensive not referencing b,c,d,e */ }
        if (b) { /* do something expensive not referencing a,c,d,e */ }
        if (c) { /* do something expensive not referencing a,b,d,e */ }
        if (d) { /* do something expensive not referencing a,b,c,e */ }
        if (e) { /* do something expensive not referencing a,b,c,d */ }
    }
}

const func = makeFunc(true, false, false, false, false)
for ( let i=0; i < 100_000; i++) func()

我希望,在这个例子中,V8 能够优化if (x)闭包上的测试,只发出

/* do something expensive not referencing b,c,d,e */

if (a)执行100,000次之后。

javascript
  • 2 2 个回答
  • 56 Views

2 个回答

  • Voted
  1. Bergi
    2025-04-30T11:59:09+08:002025-04-30T11:59:09+08:00

    据我所知,没有。(或者:也许)。

    您已将函数柯里化,使其能够进行部分求值,但这实际上仅对代码本身有帮助makeFunc。 中的代码func在每次调用时都会运行。而且 V8 不会进行任何常量传播来将a/ b/… 的值内联到 中。为什么?主要是因为它们不是常量,而是函数的参数;每次执行func时,它们的值可能都不同。if

    而真正的主要问题(或者说:你所期望的解决方案)是闭包代码的特化。闭包不是模板;即使makeFunc()创建了不同的函数对象,它们也共享相同的(字节)代码和相同的优化。从这篇关于 V8 优化的深入分析中可以看出:

    […] 我们希望在不同的闭包之间共享代码,因为为每个闭包生成一个代码对象会浪费资源(包括时间和内存),尤其是如果你使用带有高阶内置函数的箭头函数,例如

    let b = a.map(x => x + 1);
    

    您不希望每次执行此行时都运行优化编译器,只是为了为 x => x + 1 生成专门的代码对象。

    虽然我认为这不是您想要的通用答案,但您的具体示例代码确实得到了优化。但这仅仅是因为您只调用了一次该函数 :-/ 针对函数的首次调用进行优化(和专门化) 会带来可衡量的加速,因为网站上的很多函数只被调用一次。而且 V8 实际上可以进行函数上下文专门化(整篇深入探讨的文章都是关于它的!),然而,我上面省略的引用部分确实解释了 V8 就是这样做的:

    它仅在任何函数的第一次关闭时启用

    我找到的更多资源:

    • V8 在 2011 年没有进行任何持续传播
    • 您可能有更好的机会通过放入循环来获得优化代码makeFunc(true, false, false, false, false)() ,希望被调用的函数被内联,然后使用常量值进行优化
    • 与 V8 性能相关的注释和资源
    • 2
  2. Best Answer
    jmrk
    2025-04-30T17:07:15+08:002025-04-30T17:07:15+08:00

    是的,V8 对此进行了优化,只要外部上下文的变量永远不会被写入(意思是:只要不存在可以写入它们的代码)。

    这是一个反例,由于上下文变量不是常量,因此无法进行优化:

    function makeFuncs(a, b, c, d e) {
      return {
        f1: () => { if (a) { console.log("a was true"); }},
        f2: () => { a = !a; }
      }
    }
    
    let funcs = makeFuncs(true);
    funcs.f1();  // prints
    funcs.f2();
    funcs.f1();  // doesn't print
    

    显然,当f1自行优化时,编译器不能仅仅采用当前值a并假设它永远不会改变。

    但只要f2赋值a = ...语句不存在,V8 就能意识到它a永远不会被写入,因此编译器可以安全地将其视为常量。所以在原帖的例子中,if检查确实被优化掉了。

    (感谢@Dada完成这里的大部分调查!)

    • 1

相关问题

  • 合并排序不起作用 - Javascript代码:即使在调试后也无法找到错误

  • select.remove() 方法工作得很奇怪[关闭]

  • useOpenWeather() 中总是出现 401 res -react-open-weather lib [重复]

  • 输入元素没有只读属性,但字段仍然不可编辑[关闭]

  • 如何编辑 D3.js RadialTree 的第一个节点半径?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    重新格式化数字,在固定位置插入分隔符

    • 6 个回答
  • Marko Smith

    为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会?

    • 2 个回答
  • Marko Smith

    VScode 自动卸载扩展的问题(Material 主题)

    • 2 个回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Martin Hope
    Fantastic Mr Fox msvc std::vector 实现中仅不接受可复制类型 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant 使用 chrono 查找下一个工作日 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor 构造函数的成员初始化程序可以包含另一个成员的初始化吗? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský 为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul C++20 是否进行了更改,允许从已知绑定数组“type(&)[N]”转换为未知绑定数组“type(&)[]”? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann 为什么 {2,3,10} 和 {x,3,10} (x=2) 的顺序不同? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve