Dart:在多次调用的方法中编写嵌套函数是否高效
Dart: Is it efficient to write nested functions in methods that are called several times
请考虑以下代码,
class A {
foo() {
int a = logicToGetA();
int _bar() => someOtherLogic(a);
// ..
int b = _bar();
// ..
}
}
class B {
int _bar(int a) => someOtherLogic(a);
foo() {
int a = logicToGetA();
// ..
int b = _bar(a);
// ..
}
}
main() {
for (int i = 0; i < 1000000; i++) {
A().foo();
}
for (int i = 0; i < 1000000; i++) {
B().foo();
}
}
解释:class A 的 bar() 嵌套在 foo() 中,但 class B 的 bar() 嵌套在 foo() 之外。在第二种情况下,bar() 也可以作为静态方法。
我的疑问:如果 foo() 被多次调用,哪种方式更有效?如果 A().foo() 被调用 1000000 次,A.foo.bar 会被重新定义那么多次吗?
视情况而定。
如果 _bar
函数可以在 foo
方法之外定义,那么我们可以假定它不引用 foo
方法的任何局部变量。
在这种情况下,编译器 可以 优化局部函数,使其与实例方法一样高效。也许是,也许不是,让我们检查一下。
参见:https://dartpad.dev/4a53a91bf4e0006e4af4c8a598b68ee6。
这是(尝试)编写的,以便编译器无法优化 _someOtherLogic
的调用。
我还尝试将调用设为静态方法(但随后必须将对象本身作为参数传递才能为 flag
访问实例 getter)。
运行 dartpad 中的这个给了我一组最终结果
A: 918460 /ms
B: 798960 /ms
S: 918380 /ms
看起来 dart2js 使用本地函数比使用实例方法 更 高效。
运行 VM 上的相同代码给出的基准测试结果为:
A: 625960.0 /ms
B: 723245.0 /ms
S: 625075.0 /ms
表明它的性能特点与dart2js正好相反
很有可能dart2js在静态已知的情况下内联了_bar
函数。 dart2js 编译器倾向于比 VM 更积极地进行内联。
总而言之,除非函数调用大量出现在 real-world 程序的性能配置文件中,否则我不会开始担心这种差异。
如果您的程序的性能确实严重依赖于此 one 函数调用,我可能会内联该函数。如果不是,请编写更具可读性和可维护性的内容,并且在您知道它很重要之前不要开始 micro-optimizing。
请考虑以下代码,
class A {
foo() {
int a = logicToGetA();
int _bar() => someOtherLogic(a);
// ..
int b = _bar();
// ..
}
}
class B {
int _bar(int a) => someOtherLogic(a);
foo() {
int a = logicToGetA();
// ..
int b = _bar(a);
// ..
}
}
main() {
for (int i = 0; i < 1000000; i++) {
A().foo();
}
for (int i = 0; i < 1000000; i++) {
B().foo();
}
}
解释:class A 的 bar() 嵌套在 foo() 中,但 class B 的 bar() 嵌套在 foo() 之外。在第二种情况下,bar() 也可以作为静态方法。
我的疑问:如果 foo() 被多次调用,哪种方式更有效?如果 A().foo() 被调用 1000000 次,A.foo.bar 会被重新定义那么多次吗?
视情况而定。
如果 _bar
函数可以在 foo
方法之外定义,那么我们可以假定它不引用 foo
方法的任何局部变量。
在这种情况下,编译器 可以 优化局部函数,使其与实例方法一样高效。也许是,也许不是,让我们检查一下。
参见:https://dartpad.dev/4a53a91bf4e0006e4af4c8a598b68ee6。
这是(尝试)编写的,以便编译器无法优化 _someOtherLogic
的调用。
我还尝试将调用设为静态方法(但随后必须将对象本身作为参数传递才能为 flag
访问实例 getter)。
运行 dartpad 中的这个给了我一组最终结果
A: 918460 /ms
B: 798960 /ms
S: 918380 /ms
看起来 dart2js 使用本地函数比使用实例方法 更 高效。 运行 VM 上的相同代码给出的基准测试结果为:
A: 625960.0 /ms
B: 723245.0 /ms
S: 625075.0 /ms
表明它的性能特点与dart2js正好相反
很有可能dart2js在静态已知的情况下内联了_bar
函数。 dart2js 编译器倾向于比 VM 更积极地进行内联。
总而言之,除非函数调用大量出现在 real-world 程序的性能配置文件中,否则我不会开始担心这种差异。 如果您的程序的性能确实严重依赖于此 one 函数调用,我可能会内联该函数。如果不是,请编写更具可读性和可维护性的内容,并且在您知道它很重要之前不要开始 micro-optimizing。