2011-03-24 66 views
5

Tôi không chắc liệu đây có phải là sự so sánh hợp lệ hay câu lệnh hợp lệ hay không. cùng được viết bằng C và các ứng dụng được mã hóa bằng C++ thường chậm hơn trong thời gian chạy so với các ứng dụng được viết bằng C.
Có bất kỳ sự thật nào trong các câu lệnh này không?
Ngoài việc gặt hái những lợi ích của tính linh hoạt OOP mà C++ cung cấp, việc so sánh ở trên có được xem xét hoàn toàn từ phối cảnh thời gian biên dịch/thực thi không?Biên dịch và thực thi thời gian của C++ so với mã nguồn C

Tôi hy vọng rằng điều này không bị đóng cửa quá chung chung hoặc mơ hồ, nó chỉ là một nỗ lực để biết sự thật thực tế về báo cáo tôi đã nghe trong nhiều năm từ nhiều lập trình viên (C lập trình chủ yếu).

+0

Tôi cho rằng một tìm kiếm nhỏ của Google sẽ cung cấp cho hàng nghìn lượt truy cập về chủ đề này, bao gồm nhiều bài tiểu luận và tài liệu nghiên cứu. – Lundin

+4

@Lundin: Tôi tìm kiếm SO vì có một nhóm chuyên gia tuyệt vời đưa ra lời khuyên và khuyến nghị có giá trị dựa trên kinh nghiệm cá nhân và chuyên môn của họ. Sẽ không có việc sử dụng SO nếu người ta phải google và đọc hàng chục và hàng ngàn bài tiểu luận thay vì được hưởng lợi từ kinh nghiệm của các lập trình viên chuyên gia đồng nghiệp. –

+0

Sự cố với câu hỏi này là "cùng một chương trình trong C". Vấn đề là việc thực hiện một cách ngây thơ cùng một chương trình trong C không cung cấp cho bạn cùng một chương trình. Trình biên dịch C++ tạo ra nhiều mã hơn mà bạn không thực sự thấy rằng trình lập trình "C" nên thực hiện để làm cho các chương trình giống nhau. Vì vậy, bạn nên thêm một biện pháp chủ quan thứ ba để kiểm tra của bạn. Mất bao lâu để 'viết' một chương trình C++/C tương đương. Với một ứng dụng không tầm thường tôi nghi ngờ rằng sự khác biệt là đáng kể. –

Trả lời

9

Tôi sẽ trả lời một phần cụ thể của câu hỏi khá khách quan. Mã C++ sử dụng các mẫu sẽ chậm hơn để biên dịch mã C. Nếu bạn không sử dụng các mẫu (mà bạn có thể sẽ nếu bạn sử dụng thư viện chuẩn), nó sẽ là thời gian biên dịch rất giống nhau.

EDIT: Về thời gian chạy, nó chủ quan hơn nhiều. Mặc dù C có thể là một ngôn ngữ cấp thấp hơn một chút, nhưng các trình tối ưu hóa C++ đang trở nên thực sự tốt, và C++ cho chính nó tự nhiên hơn đại diện cho các khái niệm thế giới thực. Nếu nó dễ dàng hơn để đại diện cho các yêu cầu của bạn trong mã (như tôi muốn tranh luận trong C++) thì thường dễ dàng hơn để viết mã tốt hơn (và có hiệu năng cao hơn) so với ngôn ngữ khác. Tôi không nghĩ rằng có bất kỳ dữ liệu khách quan nào cho thấy C hoặc C++ nhanh hơn trong tất cả các trường hợp có thể xảy ra. Tôi thực sự khuyên bạn nên chọn ngôn ngữ của bạn dựa trên nhu cầu của dự án và sau đó viết nó bằng ngôn ngữ đó. Nếu mọi thứ quá chậm, hồ sơ và tiến hành với các kỹ thuật cải thiện hiệu suất bình thường.

+0

Có thể hiểu được trong trường hợp các mẫu như trình biên dịch cần tạo ra các chuyên ngành. –

+0

Mẫu cũng có thể tăng thời gian chạy trong một số trường hợp cực đoan do quá nội tuyến (mẫu có xu hướng khuyến khích nội tuyến vì tất cả mã cần có sẵn trong tiêu đề) và/hoặc do tăng kích thước mã (khi chúng không được gạch chân và mối liên kết không phải là đủ thông minh để hợp nhất chức năng tương ứng với sự khởi tạo khác nhau của mẫu nhưng tạo cùng một mã, suy nghĩ 'std :: vector < int* >' và 'std :: vector < float* >') có thể gây ra nhiều bộ nhớ cache hơn. –

+0

@Sylvain - Làm thế nào để viết nó trong C giúp bạn với điều đó? –

-2

Các ứng dụng C nhanh hơn để biên dịch và thực thi hơn các ứng dụng C++.

Ứng dụng C++ thường chậm hơn trong thời gian chạy và chậm hơn nhiều so với các chương trình C.

Nhìn vào những liên kết này:

+4

Tôi thấy khó tin rằng "các ứng dụng C++ thường chậm hơn khi chạy". Bạn có bằng chứng nào cho tuyên bố này không? –

+0

Một số trong những bài viết này là 5-10 tuổi. Khó liên quan nữa. –

+0

@Bo Tại sao? Tiêu chuẩn C mới nhất được phát hành cách đây 12 năm và tiêu chuẩn C++ mới nhất được phát hành cách đây 8 năm. Tôi khá chắc chắn đã không có bất kỳ thay đổi mang tính cách mạng trong hiệu quả trình biên dịch nói chung kể từ đó. – Lundin

6

Thời gian chạy của C++ so với C sẽ phải chịu chỉ khi bạn sử dụng một số C++ - các tính năng cụ thể. Các ngoại lệ và các cuộc gọi hàm ảo thêm vào thời gian chạy so với mã lỗi trả về và các cuộc gọi trực tiếp. Mặt khác, nếu bạn thấy mình sử dụng các con trỏ hàm trong C (như, nói, GTK làm) bạn đã trả ít nhất một số giá cho các hàm ảo. Và kiểm tra mã lỗi sau mỗi lần trả về hàm cũng sẽ tốn thời gian - bạn không làm điều đó khi bạn sử dụng các ngoại lệ.

Mặt khác, nội tuyến và các mẫu trong C++ có thể cho phép bạn thực hiện nhiều công việc biên dịch-thời gian - hoạt động mà C ngăn để chạy thời gian. Trong một số trường hợp, C++ có thể kết thúc nhanh hơn C.

+0

Nếu chỉ được sử dụng khi thích hợp, ngoại lệ thường sẽ dẫn đến mã số nhanh hơn (rất ít) nhanh hơn mã số trả về là . –

4

Nếu bạn biên dịch cùng mã với C và C++, sẽ không có sự khác biệt.

Nếu bạn để trình biên dịch thực hiện công việc cho bạn, chẳng hạn như mở rộng mẫu, việc này sẽ mất chút thời gian. Nếu bạn làm tương tự trong C, với cắt và dán hoặc một số macro phức tạp, thay vào đó, nó sẽ mất thời gian của bạn.

Trong một số trường hợp, mở rộng nội tuyến các mẫu sẽ thực sự dẫn đến mã chuyên biệt hơn và chạy nhanh hơn so với mã C tương đương. Giống như ở đây:

http://www2.research.att.com/~bs/new_learning.pdf

Hoặc báo cáo này cho thấy nhiều tính năng C++ không có chi phí thời gian chạy:

http://www.open-std.org/jtc1/sc22/wg21/docs/TR18015.pdf

+0

Sự cố là "Mã tương tự". Để viết cùng một mã trong C được thực hiện bởi một chương trình C++ yêu cầu kỹ sư viết mã nguồn C đáng kể hơn (vì các tính năng bổ sung của ngôn ngữ). Vì vậy, thử nghiệm "Cùng một mã" là rất chủ quan khi chỉ xem xét một chương trình không tầm thường. –

+0

@Loki Astari: Nhận xét cũ, tôi biết, nhưng Bo có thể có nghĩa là cùng một mã - ví dụ: các tập tin tương tự, một khi được biên dịch là C++ bởi g ++ và một lần bởi c bằng gcc (tất nhiên chỉ có thể nếu nó được viết trong giao điểm của c và C++). – MikeMB

+0

@MikeMB: Sau đó, bạn chỉ viết C. Chắc chắn nếu bạn viết C và biên dịch nó với g ++ và gcc thì bạn sẽ nhận được cùng một mã. Nhưng nó làm cho câu hỏi không thú vị chút nào nếu bạn nhìn theo cách đó. –

9

Tốc độ tương đối thời gian chạy là một chút khó dự đoán. Tại một thời điểm, khi hầu hết mọi người nghĩ về C++ là tất cả về thừa kế và sử dụng các hàm ảo (ngay cả khi chúng không đặc biệt thích hợp), mã được viết bằng C++ thường chậm hơn một chút so với C.

Với (điều mà hầu hết chúng ta sẽ xem xét) C++ hiện đại, ngược lại có xu hướng đúng: các mẫu cung cấp đủ tính linh hoạt trong thời gian biên dịch mà bạn có thể thường xuyên tạo mã nhanh hơn bất kỳ tương đương hợp lý nào trong C. Theo lý thuyết bạn có thể luôn luôn tránh điều đó bằng cách viết mã chuyên biệt tương đương với kết quả của việc "mở rộng" một mẫu - nhưng trong thực tế, làm như vậy là cực kỳ hiếm, và khá tốn kém.

Có một cái gì đó của một xu hướng cho C++ được viết hơi nhiều hơn thường cũng - chỉ cần ví dụ, đọc dữ liệu vào std::string hoặc std::vector (hoặc std::vector<std::string>) vì vậy người dùng có thể nhập một số lượng tùy ý các dữ liệu mà không tràn bộ đệm hoặc dữ liệu đơn giản bị cắt bớt tại một số điểm. Trong C, đây là số nhiều hơn phổ biến hơn để xem ai đó chỉ mã hóa bộ đệm có kích thước cố định và nếu bạn nhập nhiều hơn, nó sẽ tràn hoặc cắt bớt. Rõ ràng là đủ, bạn trả một cái gì đó cho điều đó - mã C++ thường kết thúc bằng cách sử dụng phân bổ động (new), thường chậm hơn so với chỉ định nghĩa một mảng. OTOH, nếu bạn viết C để thực hiện điều tương tự, bạn sẽ viết nhiều mã bổ sung, và nó thường chạy với tốc độ tương tự như phiên bản C++.

Nói cách khác, thật dễ dàng để viết C nhanh hơn đáng kể cho những thứ như điểm chuẩn và tiện ích sử dụng một lần, nhưng lợi thế tốc độ bốc hơi trong mã thực phải mạnh mẽ. Trong trường hợp thứ hai, về điều tốt nhất bạn thường có thể hy vọng là mã C tương đương với một phiên bản C++, và trong tất cả sự trung thực làm tốt như vậy là khá khác thường (ít nhất là IME).

So sánh tốc độ biên dịch không dễ dàng hơn. Một mặt, hoàn toàn đúng là các khuôn mẫu có thể chậm - ít nhất với hầu hết các trình biên dịch, các mẫu instantiating khá tốn kém. Trên cơ sở từng dòng, không có câu hỏi nào về việc C sẽ hầu như luôn nhanh hơn bất kỳ thứ gì trong C++ sử dụng nhiều mẫu. Vấn đề với điều đó là so sánh từng dòng hiếm khi có ý nghĩa nhiều - 10 dòng C++ có thể dễ dàng tương đương với hàng trăm hoặc thậm chí hàng nghìn dòng C. Miễn là bạn chỉ xem chỉ lúc biên dịch (không phải thời gian phát triển), số dư có thể ủng hộ C dù sao, nhưng chắc chắn không phải là gần bằng lãi suất ấn tượng như ban đầu có vẻ như vậy. Điều này cũng phụ thuộc rất nhiều vào trình biên dịch: ví dụ, clang thực hiện nhiều hơn lot tốt hơn gcc trong khía cạnh này (và gcc cũng đã cải thiện rất nhiều trong vài năm qua).

2

Mặc dù câu hỏi cũ của tôi tôi muốn thêm 5cents của tôi ở đây, vì tôi có lẽ không phải là người duy nhất tìm thấy câu hỏi này thông qua công cụ tìm kiếm.

tôi không thể nhận xét về tốc độ biên dịch nhưng trên thực hiện tốc độ:

Để theo sự hiểu biết của tôi, chỉ có một tính năng trong C++ mà chi phí hoạt động, ngay cả khi bạn không sử dụng nó. Tính năng này là ngoại lệ C++, bởi vì chúng ngăn cản một số tối ưu hóa trình biên dịch (đó là lý do, tại sao noexcept được giới thiệu trong C++ 11). Tuy nhiên, nếu bạn sử dụng một số loại cơ chế kiểm tra lỗi, thì ngoại lệ có thể hiệu quả hơn so với kết hợp kiểm tra giá trị trả về và một câu lệnh if else lô. Điều này đặc biệt đúng, nếu bạn phải báo cáo lỗi lên ngăn xếp.

Dù sao, nếu bạn tắt ngoại lệ trong khi biên dịch, C++ không giới thiệu chi phí, ngoại trừ những nơi bạn cố tình sử dụng các tính năng liên quan (ví dụ: bạn không phải trả tiền cho đa hình nếu bạn không sử dụng chức năng ảo), trong khi hầu hết các tính năng đều không giới thiệu chi phí thời gian chạy (quá tải, mẫu, không gian tên aso). Mặt khác, hầu hết các dạng mã chung sẽ nhanh hơn nhiều trong C++ so với c tương đương, vì C++ cung cấp các cơ chế (mẫu và lớp) dựng sẵn để thực hiện điều này. Một ví dụ điển hình là csort vs C++'s std :: sort. Phiên bản C++ thường nhanh hơn nhiều, bởi vì bên trong sắp xếp, hàm so sánh được sử dụng được biết ở thời gian biên dịch, ít nhất là lưu một cuộc gọi thông qua tra cứu hàm và trong trường hợp tốt nhất cho phép tối ưu hóa thêm nhiều trình biên dịch.

Điều đó đang được nói, "vấn đề" với C++ là dễ ẩn giấu sự phức tạp của người dùng sao cho mã dường như vô tội có thể chậm hơn nhiều so với dự kiến. Điều này chủ yếu là do quá tải nhà điều hành, đa hình và constructors/destructors, nhưng ngay cả một cuộc gọi đơn giản đến một chức năng thành viên ẩn các this-con trỏ mà cũng không phải là một NOP. Xem xét quá tải của toán tử: Khi bạn thấy * trong c, bạn biết điều này là (trên hầu hết các kiến ​​trúc) một hướng dẫn lắp ráp đơn, rẻ, trong C++ mặt khác nó có thể là một cuộc gọi hàm phức tạp (suy nghĩ về phép nhân ma trận). Điều đó không có nghĩa là, bạn có thể thực hiện cùng một chức năng trong c bất kỳ nhanh hơn nhưng trong C++ bạn không trực tiếp thấy rằng đây có thể là một hoạt động tốn kém. Destructors là một trường hợp tương tự: Trong "C++" hiện đại, bạn hầu như không thấy bất kỳ sự phá hủy rõ ràng nào thông qua xóa nhưng bất kỳ biến cục bộ nào nằm ngoài phạm vi có khả năng kích hoạt một cuộc gọi đắt tiền tới một destructor ảo. điều này (bỏ qua } tất nhiên). Và cuối cùng, một số người (đặc biệt đến từ Java) có xu hướng viết các phân cấp lớp phức tạp với nhiều chức năng ảo, trong đó mỗi cuộc gọi đến một hàm như vậy là một cuộc gọi hàm gián tiếp ẩn, khó hoặc không thể tối ưu. Vì vậy, trong khi ẩn phức tạp từ lập trình viên nói chung là một điều tốt đôi khi nó có ảnh hưởng xấu đến thời gian chạy, nếu lập trình viên không nhận thức được chi phí của các cấu trúc "dễ sử dụng" này.

Như một bản tóm tắt tôi sẽ nói, C++ giúp các lập trình viên thiếu kinh nghiệm viết mã chậm dễ dàng hơn (vì họ không thấy sự thiếu hiệu quả trong chương trình). Nhưng C++ cũng cho phép các lập trình viên giỏi viết mã "tốt", chính xác và nhanh hơn so với c - điều này cho phép họ có thêm thời gian để suy nghĩ về tối ưu hóa khi chúng thực sự cần thiết.

P.S .:
Hai điều tôi chưa đề cập (có thể là những thứ khác mà tôi đã quên) là khả năng tính toán thời gian biên dịch phức tạp (nhờ mẫu và constexpr) và từ khóa hạn chế của C++. Điều này là bởi vì đã không sử dụng một trong số họ trong các chương trình quan trọng thời gian nào được nêu ra và vì vậy tôi không thể bình luận về tính hữu ích chung của họ và lợi ích hiệu suất thế giới thực.

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