Tôi đã tính toán rộng rãi trên một vectơ lớn các số nguyên. Kích thước vectơ không thay đổi trong quá trình tính toán. Kích thước của vector thường được truy cập bởi mã. Nói chung nhanh hơn là gì: sử dụng chức năng vector::size()
hoặc sử dụng hằng số trợ giúp vectorSize
để lưu trữ kích thước của véc-tơ? Tôi biết rằng trình biên dịch thường có thể nội tuyến chức năng size()
khi thiết lập cờ trình biên dịch thích hợp, tuy nhiên, làm cho nội tuyến hàm là thứ mà trình biên dịch có thể làm nhưng không thể bị ép buộc.Hiệu suất của vector :: size(): nó có nhanh như đọc một biến không?
Trả lời
Câu hỏi vui.
Vì vậy, điều gì sẽ xảy ra?Vâng, nếu bạn gỡ lỗi với gdb bạn sẽ thấy một cái gì đó giống như biến 3 thành viên (tên không chính xác):
_M_begin
: con trỏ đến phần tử đầu tiên của mảng động_M_end
: con trỏ một quá khứ yếu tố cuối cùng của mảng động_M_capacity
: con trỏ một quá khứ yếu tố cuối cùng có thể được lưu trữ trong mảng động
việc thực hiện vector<T,Alloc>::size()
do đó thường giảm xuống còn:
return _M_end - _M_begin; // Note: _Mylast - _Myfirst in VC 2008
Giờ đây, có 2 điều cần xem xét khi liên quan đến việc tối ưu hóa thực tế càng tốt:
- chức năng này sẽ được inlined? Có lẽ: Tôi không có nhà văn biên dịch, nhưng nó là một cược tốt kể từ khi chi phí của một cuộc gọi chức năng sẽ lùn thời gian thực tế ở đây và kể từ khi nó được templated chúng tôi có tất cả các mã có sẵn trong các đơn vị dịch
- kết quả sẽ được lưu trữ (ví dụ: loại có một biến địa phương giấu tên): nó cũng có thể được, nhưng bạn sẽ không biết trừ khi bạn tháo rời các mã được tạo
Nói cách khác:
- Nếu bạn lưu trữ các
size
mình, có là một cơ hội tốt, nó sẽ nhanh như trình biên dịch có thể nhận được ... - nhưng bạn tiếp xúc với xác tàu bảo trì: nếu đột nhiên bạn sửa đổi vectơ và không cập nhật biến;)?
Dù sao đi chăng nữa, tôi thực sự nghi ngờ nó đáng giá. Đó là tối ưu hóa vi mô ở mức tốt nhất và không mang lại nhiều cải thiện.
"Kết quả sẽ được lưu trong bộ nhớ cache?" Đó là một câu hỏi có thể có 2 câu trả lời ngay cả trong một hàm duy nhất. Trình biên dịch là khá tốt trong việc tìm ra liệu và nơi họ có đủ đăng ký để lưu một kết quả trung gian. – MSalters
@MSalters: Tôi không thể đồng ý hơn. Và đặc biệt nếu trình biên dịch quyết định không có đủ dung lượng, thì việc đưa vào một biến giả có thể không mang lại bất kỳ cải tiến nào. –
Khi tôi hiểu đặc điểm kỹ thuật C++ năm 1998, vector<T>::size()
mất thời gian không đổi, không phải thời gian tuyến tính. Vì vậy, câu hỏi này có thể tóm tắt cho dù đó là nhanh hơn để đọc một biến địa phương hơn gọi một chức năng mà rất ít công việc.
do đó tôi muốn khẳng định rằng lưu trữ của size()
trong một biến địa phương sẽ tăng tốc độ chương trình của bạn bởi một lượng nhỏ, vì bạn sẽ chỉ gọi là chức năng (và do đó số lượng nhỏ liên tục của thời gian cần thiết để vector của bạn thực thi) một lần thay vì nhiều lần.
Tôi nghĩ rằng nếu trình biên dịch của bạn không đủ thông minh để nội dòng 'vector :: size', hiệu suất của bất kỳ mã nào sử dụng các thùng chứa mẫu tiêu chuẩn sẽ rất khủng khiếp. các cuộc gọi đến 'kích thước' sẽ không giúp ích gì. Vì vậy, nó không thực sự là một cuộc gọi chức năng trên cao. Nếu có, thì tất cả các lệnh gọi tới 'operator []', hoặc 'operator *' trên một trình lặp? Chúng ta có thể giả sử chúng cũng chậm và lặp lại trên vectơ bằng cách sử dụng một con trỏ bắt đầu bằng '& vec [0]'. Nếu bạn không tin tưởng vào việc thực hiện 'std :: vector', tốt nhất chỉ cần viết bằng C thay vì C++ ... –
Điều đó nói rằng, bạn có thể đúng rằng nó sẽ là một tốc độ nhỏ, không phải vì vấn đề nội tuyến mà người hỏi đang lo lắng. Ví dụ, có thể 'size' lần lượt truy cập bộ nhớ (nếu trình biên dịch không thể tự chứng minh rằng kích thước sẽ không thay đổi), trong khi sử dụng biến cục bộ cho phép trình biên dịch giữ kích thước trong thanh ghi (nếu bạn có đủ đăng ký). Bạn không bao giờ biết, về cơ bản. –
@Steve Jessop: Cũng chỉ ra. Việc tiết kiệm thời gian thực (ngay cả khi nó rất nhỏ) tất nhiên sẽ là kết quả của việc gọi hàm chỉ một lần thay vì nhiều lần, không phải từ thực tế rằng cơ chế gọi hàm chính nó đắt hơn đọc một biến. - Tuy nhiên, tôi sẽ không muốn dựa vào trình biên dịch tối ưu hóa để thực hiện cuộc gọi hàm bên ngoài vòng lặp nếu tôi có thể dễ dàng thực hiện việc này. – stakx
Trong mọi lần triển khai tôi đã thấy vector::size()
thực hiện phép trừ end()
và begin()
, tức là không nhanh như đọc biến.
Khi triển khai véc tơ, người triển khai phải chọn lựa nhanh nhất, end()
hoặc size(),
tức là lưu số lượng phần tử được khởi tạo hoặc con trỏ/vòng lặp vào phần tử sau phần tử được khởi tạo lần cuối. Nói cách khác; lặp lại bằng cách sử dụng trình lặp.
Nếu bạn lo lắng về hiệu suất size(), hãy viết chỉ mục của bạn dựa trên vòng lặp như thế này;
for (size_t i = 0, i_end = container.size(); i < i_end; ++i){
// do something performance critical
}
"Trong mỗi lần thực hiện tôi đã thấy vector :: size() thực hiện phép trừ của end() và begin(), tức là nó không nhanh như đọc một biến." - Có nhưng trình biên dịch vẫn có thể thực hiện điều đó ngoài vòng lặp trong lý thuyết, hoặc nói cách khác là về mã C++ mà bạn đang xem. –
Bạn có thể viết cho mình một hàm cho vòng lặp của bạn và gọi nó qua số std::for_each
. Nó lặp lại cho bạn, và sau đó câu hỏi của bạn trở thành tranh luận. Tuy nhiên, bạn đang giới thiệu một cuộc gọi hàm (có thể hoặc có thể không nhận được nội tuyến) cho mỗi vòng lặp lặp lại, vì vậy bạn nên cấu hình tốt nhất nếu bạn không nhận được hiệu suất mà bạn mong đợi.
Bạn đang giả định rằng kích thước() chỉ được sử dụng trong điều kiện vòng lặp. Điều gì xảy ra nếu mỗi lần lặp lại gọi 'foo (vec [i], vec.size() - i)'? Bạn không thể thực hiện cuộc gọi đó bằng cách sử dụng 'for_each'. – MSalters
Hiệu suất của vector :: size(): là nó nhanh như đọc một biến?
Có thể là không.
Liệu nó có vấn đề
Có lẽ không.
Trừ khi công việc bạn đang thực hiện cho mỗi lần lặp lại là rất nhỏ (như một hoặc hai hoạt động số nguyên), chi phí sẽ không đáng kể.
Luôn nhận hồ sơ về đơn đăng ký của bạn trước khi xem loại tối ưu hóa vi mô này. Hãy nhớ rằng ngay cả khi nó thực hiện phép trừ, trình biên dịch vẫn có thể dễ dàng tối ưu hóa nó theo nhiều cách sẽ làm mất đi bất kỳ tổn thất hiệu năng nào.
tôi luôn luôn lưu vector.size() trong một biến địa phương (Chỉ khi vector.size() không thay đổi trong vòng lặp for!).
Tại sao? Bởi vì gọi nó trên mỗi lần lặp lại và lưu nó trong một biến cục bộ nhanh hơn rất nhiều. Đó là những gì tôi đã trải nghiệm trong các ứng dụng của mình.
Tôi không thể cung cấp cho bạn bất kỳ số thực nào, nhưng nó tạo ra sự khác biệt đáng chú ý.
Và đối với tất cả những người phàn nàn về tối ưu hóa vi mô:
Khi bạn viết một vòng lặp lớn, bạn có đơn giản (chỉ để vui) chèn một phép trừ không cần thiết trong đó? Không, bạn không.
Tại sao bạn không chỉ cần cấu hình nó? Một vector lớn và std :: thời gian sẽ làm tốt.
- 1. Biến biến động 'đọc' nhanh như bình thường đọc?
- 2. Hiệu suất của OLEDB để đọc Excel
- 3. Hiệu suất Vector vs Array
- 4. Hiệu suất của StackFrame như thế nào?
- 5. Nâng cao hiệu suất của webView (nên có cùng hiệu suất như Trình duyệt web gốc)
- 6. Hiệu suất của ArrayList
- 7. tĩnh/biến dụ hiệu suất hoạt động của Java
- 8. Hiệu suất của Bộ đếm hiệu suất
- 9. .NET File nhị phân đọc hiệu suất
- 10. Hiệu suất của Interlocked.Increment
- 11. Hiệu suất của Fortran
- 12. cách hiệu quả để lấy quyền hạn của một vector
- 13. C++ cách nhanh nhất để xóa hoặc xóa một vector
- 14. Hiệu suất gây hại có hiệu quả không?
- 15. mysql như hiệu suất tăng
- 16. cách Fancy để đọc một tập tin trong C++: hiệu suất lạ vấn đề
- 17. Hiệu suất của dynamic_cast?
- 18. Hiệu suất của ID dài
- 19. Hiệu suất Overhead của AOP
- 20. Hiệu suất của OracleBulkCopy
- 21. Hiệu suất ghi thấp của Cassandra
- 22. Diễn giải hiệu suất phản chiếu Java: Tại sao nó lại rất nhanh?
- 23. Hiệu suất của Python đáng giá?
- 24. hiệu suất của ActiveRecord SessionStore
- 25. Hiệu suất của danh sách (...). Chèn (...)
- 26. Hiệu suất của DataInputStream \ DataOutputStream
- 27. Hiệu suất của Java ResourceBundle
- 28. Hiệu suất của Arrays.asList
- 29. Hiệu suất chậm của SqlDataReader
- 30. Hiệu suất: List.Count vs kiểm tra một biến lưu trữ
Sử dụng biến cục bộ rõ ràng sẽ không chậm hơn. Nếu sự khác biệt tốc độ thực sự quan trọng với bạn - hãy tính thời gian. –
Nó có mùi giống như tối ưu hóa sớm. – NomeN
@NomeN, điều này giống như tránh bi quan sớm. OP đã biết vector của anh ta rất lớn, vì vậy 'size()' sẽ được gọi rất nhiều. –