2011-12-23 29 views
22

Tôi vừa thử so sánh hiệu suất của các biểu thức lambda trong C++ 11, vì vậy tôi đã tính tổng các phần tử thử nghiệm trong một vector có giá trị double. Đây là việc thực hiện:Tại sao C++ lambda chậm hơn chức năng thông thường khi được gọi nhiều lần?

#include <vector> 
#include <algorithm> 
#include <iostream> 
#include <ctime> 

#define LOG(x) { std::cout << #x << " = " << (x) << "\n"; } 
#define TIME(t) { std::cout << ((double)(clock() - (t))/CLOCKS_PER_SEC) << " s\n"; } 

double sum(const std::vector<double>& v) 
{ 
    double s = 0.0; 
    for (auto i = v.cbegin(); i != v.cend(); ++i) 
     s += *i; 
    return s; 
} 

int main() 
{ 
    const size_t MAX = 1; // number of tests 
    const size_t SIZE = 100000000; // length of the vector 

    std::vector<double> v(SIZE, 1.0); 
    double out; 

    clock_t clk; 

    std::cout << "iterator\n"; 

    clk = clock(); 
    out = 0.0; 
    for (size_t i = 0; i < MAX; ++i) 
     out += sum(v); 
    TIME(clk) 
    LOG(out) 

    std::cout << "\nlambda\n"; 

    clk = clock(); 
    out = 0.0; 
    for (size_t i = 0; i < MAX; ++i) 
     std::for_each(v.cbegin(), v.cend(), [&](double d) { out += d; }); 
    TIME(clk) 
    LOG(out) 

    return 0; 
} 

Đây là kết quả của chương trình này (biên soạn trong VS2010 SP1, trong chế độ Release):

 
iterator 
0.32 s 
out = 1e+008 

lambda 
0.326 s 
out = 1e+008 

Như người ta có thể thấy, có thực tế không có sự khác biệt trong hoạt động. Tuy nhiên, nếu tôi đưa ra 10 làm giá trị của MAX (nó có nghĩa là tổng kết sẽ được thực hiện 10 lần thay vì một), kết quả khác nhau:

 
iterator 
0.287 s 
out = 1e+009 

lambda 
2.84 s 
out = 1e+009 

thử nghiệm cho biểu thức lambda mất nhiều thời gian hơn khoảng 10 lần. Tại sao? Tôi nghĩ rằng nó có thể được gây ra bởi thực tế, rằng trên mỗi lần lặp lambda mới được tạo ra, nhưng tôi đã thử điều này:

out = 0.0; 
auto f = [&](double d) { out += d; }; 
for (size_t i = 0; i < MAX; ++i) 
    std::for_each(v.cbegin(), v.cend(), f); 

kết quả không thay đổi. Ai đó có thể giải thích rằng hành vi đó với tôi?

+2

Điều này rất hấp dẫn! Bạn có thể thử sử dụng lambda trong một vòng lặp viết tay thay vì 'foreach'? – dasblinkenlight

+0

g ++ 4.6.2 trên linux cung cấp thời gian chạy giống hệt nhau (0,13 - 0,12 giây trên máy tính của tôi) – Cubbi

+0

Không còn sương mù, hãy kiểm tra chỉnh sửa của tôi. Sai lầm của tôi, nhưng tôi vẫn thấy nó khá thú vị. :) – Archie

Trả lời

39

Nó bật ra, rằng đây không phải là vấn đề với biểu thức lambda, chỉ cần trình biên dịch tối ưu hóa vòng ngoài trong trường hợp đầu tiên bằng cách lưu vào bộ nhớ kết quả của hàm sum(). Sau khi thay đổi trường hợp đầu tiên thành biểu mẫu này:

out = 0.0; 
for (size_t i = 0; i < MAX; ++i) 
{ 
    out += sum(v); 
    v[i] = 1.0; // this adds O(1) time and prevents caching 
} 

cả hai thời gian đều gần bằng nhau, với lambda làm mục ưa thích.

+9

Điều tra tốt. –

+3

Và đạo đức của câu chuyện - luôn kiểm tra và điểm chuẩn với mã * thực *, không bao giờ có * mã đồ chơi *. –

+2

@Archie Bạn đã thêm v [i] = 1.0 vào lambda chưa? – sprite

Các vấn đề liên quan