Performance 为什么在Rust中交换[]float64的元素比交换Vec的元素快?

Performance 为什么在Rust中交换[]float64的元素比交换Vec的元素快?,performance,go,rust,llvm-codegen,Performance,Go,Rust,Llvm Codegen,我有两个等价物?程序,一个在运行,另一个在生锈。平均执行时间为: 前进约169毫秒 锈蚀~201ms 去 包干管 进口 fmt 时间 func main{ 工作:=[]浮动64{0.00,1.00} 开始:=时间。现在 对于i:=0;i

我有两个等价物?程序,一个在运行,另一个在生锈。平均执行时间为:

前进约169毫秒 锈蚀~201ms 去

包干管 进口 fmt 时间 func main{ 工作:=[]浮动64{0.00,1.00} 开始:=时间。现在 对于i:=0;i<100000000;i++{ 工时[0],工时[1]=工时[1],工时[0] } 已用时间:=时间。自开始 fmt.println执行时间:,已过 } 生锈

我是用发行版编译的

使用std::time::Instant; fn干线{ 让mut工作:Vec=Vec::new; work.0.00; 工作时间:1.00; 让现在=瞬间::现在; 对于1..100000000中的x{ 工作效率:1; } 让过去=现在。过去; println!执行时间:{:?},已过; } 在这种情况下,生锈的性能比Go差吗?Rust程序能否以惯用的方式编写,以更快地执行

Rust程序能否以惯用的方式编写,以更快地执行

对。要创建包含少量元素的向量,请使用vec![]宏:

在我的电脑上,这比你原来的代码快30倍

为什么程序集仍然包含这个什么都不做的循环?为什么编译器不能看到两次推送与vec是相同的呢![0.0, 1.0]? 这两个问题都很好,而且都可能指向LLVM或Rust编译器中的缺陷

然而,遗憾的是,没有多少有用的信息可以从微基准测试中获得。基准测试很难,就像真的很难一样。有太多的陷阱,即使是专业人士也会上当受骗。在您的例子中,基准在几个方面存在缺陷。首先,您永远不会观察向量的内容,以后再也不会使用它。这就是为什么一个好的编译器可以像上面的Rust编译器那样删除所有甚至涉及向量的代码。所以这不好


除此之外,这与任何真正的性能关键代码都不相似。即使稍后会观察到向量,交换奇数次也等于一次交换。因此,除非您想知道优化器是否能够理解这个交换规则,否则遗憾的是,您的基准测试并没有真正的用处

不是答案,而是补充卢卡斯所写的内容, 下面是1.11 对于循环本身:

    xorl    CX, CX
    movsd   8(AX), X0
    movsd   (AX), X1
    movsd   X0, (AX)
    movsd   X1, 8(AX)
    incq    CX
    cmpq    CX, $100000000
    jlt     68
承蒙


在这两种情况下,请注意,您测量的时间很可能是由进程的启动和初始化决定的,因此您实际上没有测量循环执行的速度。看来你的方法不正确。

这种微基准不太可能产生有用的数据。我刚刚编译并运行了你的两个基准。我使用go build-o b1 bench.go表示go代码,使用rustc-o-o b2 bench.rs表示Rust代码。go基准测试耗时约180ms而Rust基准测试耗时约3msAt,如果我忽略Rust编译器的-O标志,则完成Rust基准测试大约需要5秒。此外,每晚运行的Rust编译器和稳定运行的Rust编译器之间似乎有着巨大的差异。150毫秒左右的结果稳定,仍然比Go好,但相差不大。每晚结果为2-4毫秒,比Go和stable Rust好两个数量级。@MadWombat可能是优化器学会了一些新技巧。由于作品从未被真正阅读过,因此所有的文字都无关紧要。感谢你给出的清晰而有用的答案。最初的问题是在两种语言中实现冒泡排序纯粹是为了教育价值。记忆交换是前进的方向,所以这就是我在这个问题中所包含的全部内容,可能有损于上下文/清晰度。对于100000个元素,执行时间的差异是几秒。@Kyle如果您有一个比预期慢的冒泡排序更完整的示例,您应该提出另一个问题生成的代码中最令人费解的是add eax,-11。我完全不知道这是从哪里来的。如果是偶数,我会假设优化器已经展开了那个迭代次数,并且发现偶数的交换是不可操作的。但是对于11,我真的没有主意。@SvenMarnach,这也让我困惑!我想您已经非常接近部分循环展开和LLVM优化11次迭代到一次交换中。但是为什么从11点开始却没有注意到像。。。8次迭代编译为零?也许我们应该问一个大家都在谈论的问题^_^在本例中,当您知道您的Vec不需要增长时,另一种可能性是使用固定大小的数组。在1m的迭代中,在我的旧机器上使用Criteria:original为5.0338ms,宏为4.5929ms,使用数组为3.0950n。您测量的时间主要由进程的启动和初始化决定-提供的代码OP包含时间调用。你是说Go和Rust代码除了在time.Now/time.Since或Instant::Now/Now.appeased之间循环外,还运行其他代码吗?@Shepmaster,是的,你是对的。我 站直了,谢谢。
example::main:
  mov eax, 99999999
.LBB0_1:
  add eax, -11
  jne .LBB0_1
  ret
    xorl    CX, CX
    movsd   8(AX), X0
    movsd   (AX), X1
    movsd   X0, (AX)
    movsd   X1, 8(AX)
    incq    CX
    cmpq    CX, $100000000
    jlt     68