Peter Xie
Ngày 13 tháng 7 năm 2020
4 phút đọc
Chậm hơn 45.000 lần!
Ảnh của Ben White trên unplashĐể so sánh hiệu suất tính toán giữa các ngôn ngữ Python và C, hãy để Lôi thực hiện một vòng cho tổng trong một giây. Bản thân mã là khá nhiều tự giải thích.
Python
Tôi sẽ bắt đầu bằng cách không đồng ý với một phần của câu trả lời được chấp nhận [và được trả lời tốt] cho câu hỏi này bằng cách nêu:
Thực tế có rất nhiều lý do tại sao mã JENT sẽ chạy chậm hơn một chương trình C ++ được tối ưu hóa đúng cách [hoặc ngôn ngữ khác không có thời gian chạy] bao gồm: including:
Tính toán các chu kỳ dành cho mã jit trong thời gian chạy theo định nghĩa không có sẵn để sử dụng trong thực thi chương trình.
Bất kỳ đường dẫn nóng nào trong jitter sẽ cạnh tranh với mã của bạn để hướng dẫn và bộ đệm dữ liệu trong CPU. Chúng tôi biết rằng bộ đệm thống trị khi nói đến hiệu suất và ngôn ngữ bản địa như C ++ không có loại tranh chấp này, theo thiết kế.
Ngân sách thời gian tối ưu hóa thời gian chạy nhất thiết phải bị hạn chế hơn nhiều so với số lượng tối ưu hóa thời gian biên dịch [như một nhà bình luận khác đã chỉ ra]
Điểm mấu chốt: Cuối cùng, bạn gần như chắc chắn sẽ có thể tạo ra một triển khai nhanh hơn trong C ++ so với C#..
Bây giờ, như đã nói, bao nhiêu thực sự không thể định lượng nhanh hơn bao nhiêu, vì có quá nhiều biến số: nhiệm vụ, miền vấn đề, phần cứng, chất lượng triển khai và nhiều yếu tố khác. Bạn sẽ có các bài kiểm tra trên kịch bản của mình để xác định sự khác biệt về hiệu suất, và sau đó quyết định xem nó có xứng đáng với nỗ lực và độ phức tạp bổ sung hay không.
Đây là một chủ đề rất dài và phức tạp, nhưng tôi cảm thấy đáng được đề cập vì tính đầy đủ của trình tối ưu hóa thời gian chạy của C#là tuyệt vời và có thể thực hiện một số tối ưu hóa động nhất định trong thời gian chạy đơn giản là không có sẵn cho C ++ với thời gian biên dịch của nó [thời gian biên dịch của nó [ Tĩnh] Trình tối ưu hóa. Ngay cả với điều này, lợi thế vẫn thường là sâu sắc trong tòa án của ứng dụng bản địa, nhưng trình tối ưu hóa động là lý do cho vòng loại "gần như chắc chắn" được đưa ra ở trên.almost certainly" qualifier given above.
-
Về mặt hiệu suất tương đối, tôi cũng bị xáo trộn bởi các số liệu và các cuộc thảo luận mà tôi đã thấy trong một số câu trả lời khác, vì vậy tôi nghĩ rằng tôi đã hòa nhập và đồng thời, cung cấp một số hỗ trợ cho các tuyên bố tôi đã đưa ra ở trên.
Một phần rất lớn của vấn đề với các điểm chuẩn đó là bạn không thể viết mã C ++ như thể bạn đang viết C# và hy vọng sẽ nhận được kết quả đại diện [ví dụ: thực hiện hàng ngàn phân bổ bộ nhớ trong C ++ sẽ cung cấp cho bạn những con số khủng khiếp.]
Thay vào đó, tôi đã viết mã C ++ thành ngữ hơn một chút và so sánh với mã C# @Wiory được cung cấp. Hai thay đổi chính tôi đã thực hiện đối với mã C ++ là:
Vector đã qua sử dụng :: Dự trữ []
Làm phẳng mảng 2D thành 1D để đạt được bộ nhớ cache tốt hơn [khối liền kề]
C# [.NET 4.6.1]
private static void TestArray[]
{
const int rows = 5000;
const int columns = 9000;
DateTime t1 = System.DateTime.Now;
double[][] arr = new double[rows][];
for [int i = 0; i < rows; i++]
arr[i] = new double[columns];
DateTime t2 = System.DateTime.Now;
Console.WriteLine[t2 - t1];
t1 = System.DateTime.Now;
for [int i = 0; i < rows; i++]
for [int j = 0; j < columns; j++]
arr[i][j] = i;
t2 = System.DateTime.Now;
Console.WriteLine[t2 - t1];
}
Thời gian chạy [Phát hành]: init: 124ms, Fill: 165ms
C ++ 14 [Clang v3.8/C2]
#include
#include
auto TestSuite::ColMajorArray[]
{
constexpr size_t ROWS = 5000;
constexpr size_t COLS = 9000;
auto initStart = std::chrono::steady_clock::now[];
auto arr = std::vector[];
arr.reserve[ROWS * COLS];
auto initFinish = std::chrono::steady_clock::now[];
auto initTime = std::chrono::duration_cast[initFinish - initStart];
auto fillStart = std::chrono::steady_clock::now[];
for[auto i = 0, r = 0; r < ROWS; ++r]
{
for [auto c = 0; c < COLS; ++c]
{
arr[i++] = static_cast[r * c];
}
}
auto fillFinish = std::chrono::steady_clock::now[];
auto fillTime = std::chrono::duration_cast[fillFinish - fillStart];
return std::make_pair[initTime, fillTime];
}
Thời gian chạy [phát hành]: init: 398
Tổng thời gian chạy: C#: 289ms, C ++ 152ms [nhanh hơn khoảng 90%]
Quan sát
Thay đổi triển khai C# thành cùng một triển khai mảng 1D mang lại init: 40ms, Fill: 171ms, Total: 211ms [C ++ vẫn nhanh hơn gần 40%].C++ was still almost 40% faster].
Việc thiết kế và viết mã "nhanh" trong C ++ khó hơn nhiều so với việc viết mã "thông thường" bằng ngôn ngữ.
Thật dễ dàng [có lẽ] dễ dàng để có được hiệu suất kém trong C ++; Chúng tôi đã thấy rằng với hiệu suất vectơ không được bảo vệ. Và có rất nhiều cạm bẫy như thế này.
Hiệu suất của C#là khá tuyệt vời khi bạn xem xét tất cả những gì đang diễn ra trong thời gian chạy. Và hiệu suất đó tương đối dễ dàng để truy cập.
Thêm dữ liệu giai thoại so sánh hiệu suất của C ++ và C#: //benchmarksgame.alioth.debian.org/u64q/compare.php?lang=gpp&lang2=csharpcore
Điểm mấu chốt là C ++ cung cấp cho bạn nhiều quyền kiểm soát hiệu suất hơn. Bạn có muốn sử dụng một con trỏ? Một tài liệu tham khảo? Bộ nhớ xếp chồng? Đống? Đa hình động hoặc loại bỏ chi phí thời gian chạy của VTable với đa hình tĩnh [thông qua các mẫu/CRTP]? Trong C ++, bạn phải ... er, hãy tự mình thực hiện tất cả các lựa chọn này [và hơn thế nữa], lý tưởng nhất là giải pháp của bạn giải quyết tốt nhất vấn đề bạn đang giải quyết.
Hãy tự hỏi mình nếu bạn thực sự muốn hoặc cần sự kiểm soát đó, bởi vì ngay cả đối với ví dụ tầm thường ở trên, bạn có thể thấy rằng mặc dù có một sự cải thiện đáng kể về hiệu suất, nhưng nó đòi hỏi một khoản đầu tư sâu hơn để truy cập.