2009-12-19 37 views
11

Tôi đã có hai chương trình với tôi, cả hai đều đang làm chính xác cùng một nhiệm vụ. Họ chỉ cần thiết lập một mảng/vector boolean với giá trị đúng. Chương trình sử dụng vector mất 27 giây để chạy trong khi chương trình liên quan đến mảng có kích thước lớn hơn 5 lần mất ít hơn 1 giây. Tôi muốn biết lý do chính xác là tại sao có sự khác biệt lớn như vậy? Là vectơ thực sự không hiệu quả?C++ Vector vs Array (Thời gian)

vectơ Chương trình sử dụng

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

using namespace std; 

int main(){ 
const int size = 2000; 
time_t start, end; 
time(&start); 
vector<bool> v(size); 
for(int i = 0; i < size; i++){ 
    for(int j = 0; j < size; j++){ 
    v[i] = true; 
    } 
} 
time(&end); 
cout<<difftime(end, start)<<" seconds."<<endl; 
} 

Runtime - 27 giây

Chương trình sử dụng mảng

#include <iostream> 
#include <ctime> 

using namespace std; 

int main(){ 
const int size = 10000; // 5 times more size 
time_t start, end; 
time(&start); 
bool v[size]; 
for(int i = 0; i < size; i++){ 
    for(int j = 0; j < size; j++){ 
    v[i] = true; 
    } 
} 
time(&end); 
cout<<difftime(end, start)<<" seconds."<<endl; 
} 

Runtime - < 1 giây

Nền tảng - Visual Studio 2008 OS - Windows Vista 32 bit SP 1 Processor Intel (R) Pentium (R) Dual CPU T2370 @ 1.73GHz Memory (RAM) 1.00 GB

Cảm ơn

Amare

+5

std :: vector không phải là vùng chứa. Đọc: http://www.gotw.ca/publications/mill09.htm –

+0

Lưu ý quan trọng: Mặc dù bạn đến đúng kết luận, nhưng bạn không thực hiện so sánh đúng. Bạn thực hiện N^2 vòng lặp của vòng lặp trong cùng (câu lệnh 'v [i] = true'), nhưng N là 2000 trong một bài kiểm tra và 10000 trong một bài kiểm tra khác, vì vậy bạn thực sự làm 25 lần nhiều công việc, chứ không phải 5 gấp nhiều lần, ngoài sự khác biệt giữa 'vectơ' và một mảng đơn giản. Điều này thực sự làm cho sự khác biệt thậm chí còn rõ rệt hơn. –

+1

@ user235022 Bạn có nghĩa là 'v [j] = true;' thay vì 'v [i] = true'? Nếu không, nó sẽ rất đơn giản cho trình biên dịch để tối ưu hóa vòng lặp nội bộ, vì các hành động của bạn không phụ thuộc vào biến vòng lặp. – fiktor

Trả lời

42

Bạn đang sử dụng std :: vector của bool và đó không phải là điều bạn nghĩ!

vectơ của bool là một chuyên gia mẫu con khốn mà không bao giờ nên tồn tại và thực sự lưu trữ 1 bool trong mỗi bit. Truy cập vào nó phức tạp hơn do mặt nạ và chuyển logic, vì vậy chắc chắn sẽ hơi chậm hơn.

Click here for some info on vector of bool.

Ngoài ra, bạn có thể chạy một xây dựng được tối ưu hóa (gần như chắc chắn cho những lần bạn được liệt kê, 27 giây là quá đáng với giá 4 triệu lần lặp). Thư viện mẫu chuẩn dựa rất nhiều vào trình tối ưu hóa để thực hiện những việc như các cuộc gọi hàm nội tuyến và các thời điểm elide. Thiếu tối ưu hóa này gây ra sự xuống cấp hiệu năng đặc biệt nặng nề đối với vectơ của bool vì nó phải trả về một đối tượng proxy khi bạn chỉ mục vào nó, bởi vì bạn không thể lấy địa chỉ của một chút, vì vậy toán tử [] không thể trả về một tài liệu tham khảo.

Click here for more info on proxied containers (Nửa cuối cùng là về vector của bool)

Bên cạnh việc triển khai nhiều STL có bit gỡ lỗi hữu ích mà không phải là một phần của tiêu chuẩn mà giúp bạn nắm bắt lỗi, nhưng thực sự kéo hiệu suất xuống. Bạn sẽ muốn đảm bảo những người đó bị vô hiệu hóa trong bản dựng được tối ưu hóa của bạn.

Khi bạn bật trình tối ưu hóa, hãy cài đặt đúng (nghĩa là không bật gỡ lỗi STL) và thực sự kiểm tra cùng một điều trong cả hai vòng, bạn sẽ thấy hầu như không có sự khác biệt.

tôi bị buộc phải vòng lặp của bạn lớn hơn nhiều để thử nghiệm trên máy tính của tôi, nhưng đây là hai bản xây dựng của vector lại vòng lặp bool trên máy tính của tôi, cho thấy tác động của cờ ưu trên mã STL

$ g++ main.cpp 
$ ./a.out 
17 seconds. 
$ g++ -O2 main.cpp 
$ ./a.out 
1 seconds. 
+0

Ya tôi cũng nghĩ như vậy. Tôi chạy cùng một kịch bản và nó đã gần như cùng một lúc. – Vivek

+2

VC2005 + nói riêng đã kiểm tra xác thực và kiểm tra xác thực lặp để gỡ lỗi xây dựng cho tất cả các đối tượng STL. –

+0

Cảm ơn don.neufeld, lời giải thích của bạn cũng như liên kết thực sự hữu ích. Tốt để tìm hiểu điều gì đó mới :-) – user235022

2

câu trả lời khác là rất tốt, nhưng bạn có thể dễ dàng trả lời nó cho mình bằng cách this method.

THÊM: Để trả lời nhận xét, hãy để tôi cho bạn biết ý tôi là gì. Tôi đang chạy VC trên Windows, nhưng điều này hoạt động trên bất kỳ ngôn ngữ/hệ điều hành. Tôi đã lấy chương trình đầu tiên của bạn và tăng kích thước lên 20000 vì vậy nó sẽ chạy đủ lâu. Sau đó, trong khi nó đang chạy, tôi đã lấy một số stackshots. Tất cả họ đều giống như thế này:

std::vector<bool,std::allocator<bool> >::begin() line 93 + 25 bytes 
std::vector<bool,std::allocator<bool> >::operator[]() line 132 + 37 bytes 
main() line 24 + 12 bytes 
mainCRTStartup() line 206 + 25 bytes 
KERNEL32! 7c817077() 

Vì vậy, những gì mà nói là nó được dành chủ yếu tất cả của nó là thời gian trong hoạt động lập chỉ mục trên dòng 24, và lý do nó dành thời gian đó là các nhà điều hành [] là gọi nhà điều hành begin. Cụ thể hơn:

main() line 24 + 12 bytes 

là mã này:

for(int j = 0; j < size; j++){ 
==> v[i] = true; 
} 

mà các cuộc gọi:

std::vector<bool,std::allocator<bool> >::operator[]() line 132 + 37 bytes 

đó là mã này (mà tôi định dạng lại một chút):

reference operator[](size_type _P){ 
==> return (*(begin() + _P)); 
} 

gọi:

std::vector<bool,std::allocator<bool> >::begin() line 93 + 25 bytes 

được làm điều này (chi tiết hơn):

92:  iterator begin() 
93:   {return (_First); } 
00402890 push  ebp 
00402891 mov   ebp,esp 
00402893 sub   esp,44h 
00402896 push  ebx 
00402897 push  esi 
00402898 push  edi 
00402899 push  ecx 
0040289A lea   edi,[ebp-44h] 
0040289D mov   ecx,11h 
004028A2 mov   eax,0CCCCCCCCh 
004028A7 rep stos dword ptr [edi] 
004028A9 pop   ecx <=============== 
004028AA mov   dword ptr [ebp-4],ecx 
004028AD mov   eax,dword ptr [ebp-4] 
004028B0 mov   eax,dword ptr [eax+4] 
004028B3 pop   edi 
004028B4 pop   esi 
004028B5 pop   ebx 
004028B6 mov   esp,ebp 
004028B8 pop   ebp 
004028B9 ret 

gì nó đang làm là viết 68 byte của 0xCC trên stack (vì một lý do debug) như một phần của nhận địa chỉ begin của vectơ, như một phần của việc tính toán địa chỉ của v[i], trước khi thực hiện nhiệm vụ.

Phần thời gian mà nó dành cho việc này là gần 100%, bởi vì nó đang thực hiện nó trên mỗi một số mẫu được lấy. Bạn có thể đoán rằng đó là những gì nó đã được chi tiêu gần như tất cả thời gian của nó làm? Tôi không thể.

Đây là, tất nhiên, một bản dựng Gỡ lỗi. Nếu bạn chuyển sang bản phát hành Bản phát hành, nhưng bật thông tin gỡ lỗi, tất cả các chức năng này sẽ được inline và tối ưu hóa, vì vậy nó sẽ nhanh hơn gấp 30 lần, và một lần nữa stackshots nói chính xác những gì nó đang làm.

Vì vậy, - mọi người có thể cho bạn biết những gì nó có thể được làm, nhưng điều này cho thấy làm thế nào để tìm hiểu cho chính mình những gì nó là thực sự làm.

Trên môi trường của bạn, chắc chắn nó sẽ khác.

+1

có thực sự. Thay vì hiểu các thuộc tính của cơ sở dữ liệu thư viện chuẩn, hãy chỉ cho anh ta thông tin về cách cấu hình mã của bạn ** trong một hệ điều hành khác so với việc anh ta thực sự đang sử dụng **. Và nếu bạn đã từng cố gắng gỡ lỗi hoặc hồ sơ hoặc đọc các bộ chứa thư viện chuẩn, bạn sẽ biết rằng nó không chính xác dễ đọc. Profiling có thể cho bạn biết những dòng mã nào gây ra sự chậm lại, nhưng nó có thể không trả lời câu hỏi về * những gì đang xảy ra *. – jalf

+0

@jalf: Thôi nào. Nó ** độc lập với OS **, và lược tả vì nó thường được hiểu có thể không cho bạn biết điều gì đang diễn ra, nhưng các bức ảnh sẽ cho bạn biết chính xác những gì đang diễn ra * miễn là có mã nguồn của các thư viện. –

+0

... Đó là cưa cũ về việc cho ai đó một con cá so với việc dạy chúng cá. –

1

std::vector<bool> được tối ưu hóa cho mức tiêu thụ bộ nhớ thay vì hiệu suất.

Bạn có thể đánh lừa nó bằng cách sử dụng std::vector<int>. Bạn không nên có những hạn chế về hiệu năng.

+0

Đã sửa lỗi bài đăng của bạn để sử dụng định dạng mã. Các dấu ngoặc nhọn biến mất mà không có nó – jalf

+0

Thay vì 'vector ' Tôi đề nghị 'vector ' (hoặc 'unsigned char', hoặc nếu trình biên dịch hỗ trợ nó' std :: uint8_t'). Không có lý do để sử dụng nhiều không gian hơn bạn cần. Nhưng chắc chắn không phải 'vector '. – AFoglia

+0

Lý do sử dụng nhiều không gian hơn là tốc độ tốt hơn trên hầu hết các kiến ​​trúc 32 bit. –

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