2015-10-13 74 views
0

作为一个练习,我试图微观优化Rust 1.3.0中的代码。我有一个循环遍历数组。是这样的:Rust是否优化了计算范围内的循环?

loop { 
    for i in 0..arr.len() { 
     // something happens here 
    } 
} 

由于阵列在锈病固定大小,将编译器通过评估arr.len()只是一次,并重新使用值优化代码,或将表达与所述顶层每个循环过程进行评估?这个问题可以扩展到更多的计算繁重的功能,没有副作用,除了arr.len()

换句话说,将上面的代码等同于这样的:

let arr_len = arr.len(); 

loop { 
    for i in 0..arr_len { 
     // something happens here 
    } 
} 
+2

请注意,如果您对优化感兴趣,尝试使用迭代器而不是索引到切片中通常是一个好主意,这对于边界检查具有一定的开销。如果可能,请使用'for v in&arr'。 – Shepmaster

回答

2

..是一个范围运算符,其形成Range<Idx>对象(或其衍生物:RangeFromRangeFullRangeTo)。这些对象只包含索引(Idx类型),因此您可以放心,.len()仅被评估一次。


在一般情况下,它是考察LLVM IR是个好主意。如果你有一个综合的例子,你可以很容易地使用操场。对于example

// A black-box prevents optimization, and its calls are easy to spot. 
extern { 
    fn doit(i: i32) ->(); 
} 

fn main() { 
    let arr = [1, 2, 3, 4, 5]; 

    for i in 0..arr.len() { 
     unsafe { doit(arr[i]); } 
    } 
} 

产生以下功能:

; Function Attrs: uwtable 
define internal void @_ZN4main20hd87dea49c835fe43laaE() unnamed_addr #1 { 
entry-block: 
    tail call void @doit(i32 1) 
    tail call void @doit(i32 2) 
    tail call void @doit(i32 3) 
    tail call void @doit(i32 4) 
    tail call void @doit(i32 5) 
    ret void 
} 

在这种情况下,具有固定长度的,不存在环在所有:它已被展开。

+0

这与我编辑前的回答基本相似,以回应本杰明林德利的评论。 –

+0

@JerryCoffin:恐怕我从来没有见过你的答案的前一个版本:/ –

4

至少在一个快速检查使用arr.len()嵌套在另一个环内,没有代码似乎为“呼叫”,以将要产生arr.len()。在生成的代码中,数组的大小只是硬编码到输出中。

换句话说,我不希望你的第二个代码段比第一个执行得更快。

+2

我认为OP指的是整个for循环体的多次执行,而您正在寻找(纠正我,如果我错了)for循环的单个执行的迭代。换句话说,他想知道每次for循环开始时是否再次计算范围范围,即使它们不能改变(因为数组长度不能改变)。注意他的for循环嵌套在另一个循环中。 –

+0

@BenjaminLindley:糟糕 - 我认为你是对的。 –

+0

@ BenjaminLindley是的,这正是我的意思。 –