- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
这是一个简单的程序。测试环境:debian 8,go 1.4.2
联合.go:
package main
import "fmt"
type A struct {
t int32
u int64
}
func test() (total int64) {
a := [...]A{{1, 100}, {2, 3}}
for i := 0; i < 5000000000; i++ {
p := &a[i%2]
total += p.u
}
return
}
func main() {
total := test()
fmt.Println(total)
}
联合.c:
#include <stdio.h>
struct A {
int t;
long u;
};
long test()
{
struct A a[2];
a[0].t = 1;
a[0].u = 100;
a[1].t = 2;
a[1].u = 3;
long total = 0;
long i;
for (i = 0; i < 5000000000; i++) {
struct A* p = &a[i % 2];
total += p->u;
}
return total;
}
int main()
{
long total = test();
printf("%ld\n", total);
}
结果比较:
Go:
257500000000
real 0m9.167s
user 0m9.196s
sys 0m0.012s
C:
257500000000
real 0m3.585s
user 0m3.560s
sys 0m0.008s
go好像编译了很多奇怪的汇编代码(可以用objdump -D查看)
例如,为什么 movabs $0x12a05f200,%rbp
出现两次?
400c60: 31 c0 xor %eax,%eax
400c62: 48 bd 00 f2 05 2a 01 movabs $0x12a05f200,%rbp
400c69: 00 00 00
400c6c: 48 39 e8 cmp %rbp,%rax
400c6f: 7d 46 jge 400cb7 <main.test+0xb7>
400c71: 48 89 c1 mov %rax,%rcx
400c74: 48 c1 f9 3f sar $0x3f,%rcx
400c78: 48 89 c3 mov %rax,%rbx
400c7b: 48 29 cb sub %rcx,%rbx
400c7e: 48 83 e3 01 and $0x1,%rbx
400c82: 48 01 cb add %rcx,%rbx
400c85: 48 8d 2c 24 lea (%rsp),%rbp
400c89: 48 83 fb 02 cmp $0x2,%rbx
400c8d: 73 2d jae 400cbc <main.test+0xbc>
400c8f: 48 6b db 10 imul $0x10,%rbx,%rbx
400c93: 48 01 dd add %rbx,%rbp
400c96: 48 8b 5d 08 mov 0x8(%rbp),%rbx
400c9a: 48 01 f3 add %rsi,%rbx
400c9d: 48 89 de mov %rbx,%rsi
400ca0: 48 89 5c 24 28 mov %rbx,0x28(%rsp)
400ca5: 48 ff c0 inc %rax
400ca8: 48 bd 00 f2 05 2a 01 movabs $0x12a05f200,%rbp
400caf: 00 00 00
400cb2: 48 39 e8 cmp %rbp,%rax
400cb5: 7c ba jl 400c71 <main.test+0x71>
400cb7: 48 83 c4 20 add $0x20,%rsp
400cbb: c3 retq
400cbc: e8 6f e0 00 00 callq 40ed30 <runtime.panicindex>
400cc1: 0f 0b ud2
...
而 C 程序集更干净:
0000000000400570 <test>:
400570: 48 c7 44 24 e0 64 00 movq $0x64,-0x20(%rsp)
400577: 00 00
400579: 48 c7 44 24 f0 03 00 movq $0x3,-0x10(%rsp)
400580: 00 00
400582: b9 64 00 00 00 mov $0x64,%ecx
400587: 31 d2 xor %edx,%edx
400589: 31 c0 xor %eax,%eax
40058b: 48 be 00 f2 05 2a 01 movabs $0x12a05f200,%rsi
400592: 00 00 00
400595: eb 18 jmp 4005af <test+0x3f>
400597: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
40059e: 00 00
4005a0: 48 89 d1 mov %rdx,%rcx
4005a3: 83 e1 01 and $0x1,%ecx
4005a6: 48 c1 e1 04 shl $0x4,%rcx
4005aa: 48 8b 4c 0c e0 mov -0x20(%rsp,%rcx,1),%rcx
4005af: 48 83 c2 01 add $0x1,%rdx
4005b3: 48 01 c8 add %rcx,%rax
4005b6: 48 39 f2 cmp %rsi,%rdx
4005b9: 75 e5 jne 4005a0 <test+0x30>
4005bb: f3 c3 repz retq
4005bd: 0f 1f 00 nopl (%rax)
谁能解释一下?谢谢!
最佳答案
主要区别在于数组边界检查。在 Go 程序的反汇编转储中,有:
400c89: 48 83 fb 02 cmp $0x2,%rbx
400c8d: 73 2d jae 400cbc <main.test+0xbc>
...
400cbc: e8 6f e0 00 00 callq 40ed30 <runtime.panicindex>
400cc1: 0f 0b ud2
因此,如果 %rbx
大于或等于 2,那么它会跳转到对 runtime.panicindex
的调用。鉴于您正在使用大小为 2 的数组,这显然是边界检查。您可以提出这样的论点,即编译器应该足够聪明,可以在这种可以静态确定索引范围的特定情况下跳过边界检查,但它似乎还不够聪明,无法这样做。
虽然您看到此微基准测试有明显的性能差异,但可能值得考虑这是否真的代表了您的实际代码。如果您在循环中做其他事情,差异可能不太明显。
虽然边界检查确实有成本,但在许多情况下,它比程序继续未定义行为的替代方案要好。
关于戈朗 : index efficiency of array,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31555672/
我在一个数据集中有一个来自不同来源的姓名列表:一组按 FirstName LastName 组织;另一个有全名。我想查看名字或姓氏是否在全名列中,并创建一个标志。两个问题: 首先,我 u sed th
我一直认为不存在是正确的方法,而不是使用不存在条件。但是,我对我一直使用的查询进行比较,我注意到“Not In”条件的执行实际上似乎更快。任何关于为什么会出现这种情况的见解,或者如果到目前为止我只是做
我需要开发一个 iPad 应用程序,它应该管理两种方向模式(横向和纵向)。 根据 official Apple iOS documentation , 有 2 种方法可以继续。 -第一个包括在收到旋转
我有一个类有 2 个变量成员: class A: fullname = "" email = "" 内存中存储了一个A的列表,现在我需要针对全名或电子邮件进行搜索,搜索需要支持模糊搜索
哪个更有效率?或者它们都同样有效?带星号的行中的底层架构发生了什么? (1) for(int i = m_size; i > index; --i) { int k = normalize(
要检查两个不同日期范围的重叠,{Start1, End1} 和 {Start2, End2} 我正在检查: if ((Start1 = Start2)) { //overlap exists }
这个问题在这里已经有了答案: 关闭 13 年前. Possible Duplicate: Is there a performance difference between i++ and ++i i
前言: 学习ComfyUI是一场持久战, efficiency-nodes-comfyui是提高工作流创造效率的工具,包含效率节点整合工作流中的基础功能,比如Efficient Loader节点相当
我正在编写一个 Java 小程序,并且正在尝试读取一个 220K 行 (9.2 MB) 的文本文件,该文件是用 .jar 归档的。我相信我对文本文件的唯一合理访问是InputStream。为了使用 I
我有一个 Java 应用程序,需要播放一些不同的“声音/连复段”来指示状态。我想知道是否最好将这些记录为音频文件(wav 或任何格式)并使用 Java 音频类播放它们,或者存储 MIDI 数据并使用
就目前情况而言,这个问题不太适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、民意调查或扩展讨论。如果您觉得这个问题可以改进并可能重新开放,visit
很抱歉这个问题太基本了。 目标:这是我的软件程序的输出: 1 590 SC 1.000 LEU2_YEAST 100% 1 590 EC 1.000 LEU2_ECOLI 10
重复使用 $(this) 是否有效,还是将其保存到变量中更好?我已经看到它在很多 jQuery 代码中重复使用,但由于它是对构造函数的调用,我认为它应该不必要地慢,我错了吗? 最佳答案 只是为了好玩
我正在考虑编写一个函数,该函数使用 calloc 创建一个数组来容纳文件中的数据(目前以字符形式)。据我了解,我的两个最明显的选择是读取所有字符以获得所需的总大小,使用 calloc 分配所需的空间,
好的,假设我有如下类: public class KPIObject // Data { get; set; } public string Caption { get; set; } } p
我想对表演者数组进行排序,以便他们按名字的第一个字符进行分组。例如,以下输出中的“A”代表名字以“A”开头的表演者的集合。 [ "A"[Performer,Performer,Performer,Pe
我正在使用此 MySQL 语句来查找社区的平均特性评估。问题是我必须为每个邻域添加一条 SELECT 语句——而且有很多邻域。有没有办法不必指定“RIVER FRONT”或“OLD TOWN”?有没有
我有许多表,大约有四个,我希望连接在一起。为了使我的代码更清晰和可读(对我而言),我希望一次加入所有代码,然后在最后过滤: SELECT f1, f2, ..., fn FROM t1 INNER J
我有以下代码: setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); # statement handle (prevents in
我有一个巨大的数据文件,我只需要这个文件中的特定数据,以后我会经常使用这些数据。那么这两种方法中哪一种更有效: 将此数据保存在全局变量(可能是 LinkedList)中,并在每次需要时使用它们 将它们
我是一名优秀的程序员,十分优秀!