C ++ nhanh hơn C # bao nhiêu?


245

Hay bây giờ là cách khác?

Từ những gì tôi đã nghe, có một số lĩnh vực trong đó C # chứng tỏ là nhanh hơn C ++, nhưng tôi chưa bao giờ có đủ can đảm để tự mình kiểm tra nó.

Nghĩ rằng bất kỳ ai trong số các bạn có thể giải thích những khác biệt này một cách chi tiết hoặc chỉ cho tôi đến đúng nơi để biết thông tin về điều này.


7
Được bảo vệ, để ngăn chặn bất kỳ điểm chuẩn ngẫu nhiên hơn được đăng. Nếu bạn nghĩ rằng bạn có thể đưa ra trường hợp của mình, bạn sẽ cần 10 đại diện để làm như vậy.
Robert Harvey

2
Làm thế nào điều này không được đóng như ý kiến ​​/ lập luận? Tôi vẫn chưa vào StackOverflow chứ? (Không gợi ý sự gần gũi, chỉ tò mò. Tôi thích những câu hỏi thúc đẩy tranh luận)
Bill K

1
Đây gần như là một câu hỏi tranh luận, cho rằng chúng ta đang sống trong thời đại mà IL có thể được chuyển đổi thành CPP và được tối ưu hóa từ đó: docs.unity3d.com/Manual/IL2CPP.html
pixelpax

Một ngôn ngữ kiểm tra truy cập ngoài phạm vi sẽ không bao giờ vượt trội so với ngôn ngữ không có.
Seva Alekseyev ngày

@SevaAlekseyev Không phải là ngôn ngữ làm việc này mà là trình biên dịch. Một trong những lý do C ++ là nhanh chóng (ngoài những lý do rõ ràng) là trình biên dịch C ++ đã tồn tại trong 35 năm qua (nếu không nói là nhiều hơn). Không có gì ngăn cản trình biên dịch C # trở nên tốt hơn theo thời gian. Đối với trường hợp bạn đề cập, vui lòng đọc stackoverflow.com/questions/16713076/ trên
Bẫy

Câu trả lời:


342

Không có lý do nghiêm ngặt tại sao một ngôn ngữ dựa trên mã byte như C # hoặc Java có JIT không thể nhanh như mã C ++. Tuy nhiên, mã C ++ được sử dụng để nhanh hơn đáng kể trong một thời gian dài và ngày nay vẫn còn trong nhiều trường hợp. Điều này chủ yếu là do các tối ưu hóa JIT tiên tiến hơn rất phức tạp để thực hiện và những điều thực sự tuyệt vời chỉ mới xuất hiện ngay bây giờ.

Vì vậy, C ++ nhanh hơn, trong nhiều trường hợp. Nhưng đây chỉ là một phần của câu trả lời. Các trường hợp trong đó C ++ thực sự nhanh hơn, là các chương trình được tối ưu hóa cao, trong đó các lập trình viên chuyên gia đã tối ưu hóa triệt để địa ngục. Điều này không chỉ rất tốn thời gian (và do đó tốn kém), mà còn thường dẫn đến lỗi do tối ưu hóa quá mức.

Mặt khác, mã trong các ngôn ngữ được thông dịch sẽ nhanh hơn trong các phiên bản sau của thời gian chạy (.NET CLR hoặc Java VM) mà không cần bạn làm gì cả. Và có rất nhiều tối ưu hóa hữu ích Trình biên dịch JIT có thể làm điều đó đơn giản là không thể trong các ngôn ngữ có con trỏ. Ngoài ra, một số ý kiến ​​cho rằng việc thu gom rác nói chung nên nhanh hoặc nhanh hơn quản lý bộ nhớ thủ công và trong nhiều trường hợp là như vậy. Nói chung, bạn có thể thực hiện và đạt được tất cả những điều này trong C ++ hoặc C, nhưng nó sẽ phức tạp hơn và dễ bị lỗi hơn.

Như Donald Knuth đã nói, "tối ưu hóa sớm là gốc rễ của mọi tội lỗi". Nếu bạn thực sự biết chắc chắn rằng ứng dụng của bạn sẽ bao gồm số học rất quan trọng về hiệu năng và đó sẽ là nút cổ chai, và chắc chắn nó sẽ nhanh hơn trong C ++ và bạn chắc chắn rằng C ++ sẽ không xung đột với người khác của bạn yêu cầu, đi cho C ++. Trong mọi trường hợp khác, trước tiên hãy tập trung triển khai ứng dụng của bạn một cách chính xác bằng bất kỳ ngôn ngữ nào phù hợp với bạn nhất, sau đó tìm các tắc nghẽn về hiệu suất nếu nó chạy quá chậm, sau đó suy nghĩ về cách tối ưu hóa mã. Trong trường hợp xấu nhất, bạn có thể cần gọi mã C thông qua giao diện chức năng nước ngoài, do đó bạn vẫn có khả năng viết các phần quan trọng bằng ngôn ngữ cấp thấp hơn.

Hãy nhớ rằng việc tối ưu hóa một chương trình chính xác tương đối dễ dàng, nhưng khó hơn nhiều để sửa một chương trình được tối ưu hóa.

Cho tỷ lệ phần trăm thực tế của lợi thế tốc độ là không thể, nó chủ yếu phụ thuộc vào mã của bạn. Trong nhiều trường hợp, việc thực hiện ngôn ngữ lập trình thậm chí không phải là nút cổ chai. Lấy điểm chuẩn tại http://benchmarkgame.alioth.debian.org/ với rất nhiều sự hoài nghi, vì những phần lớn này kiểm tra mã số học, rất có thể không giống với mã của bạn.


92
Mã <quote> trong các ngôn ngữ được giải thích sẽ nhanh hơn trong các phiên bản sau của thời gian chạy </ quote> Vì mã được biên dịch bởi phiên bản tốt hơn của trình biên dịch cũng sẽ nhanh hơn.
Martin York

47
Trong thực tế, có ít nhất một lý do: JIT cần phải nhanh và không thể dành thời gian cho các tối ưu hóa nâng cao khác nhau có sẵn cho trình biên dịch C ++.
Nemanja Trifunovic

63
"nhưng cũng thường dẫn đến lỗi do tối ưu hóa quá mức." [trích dẫn rất cần thiết]. Tôi làm việc tại một phòng thí nghiệm quốc gia và chúng tôi tối ưu hóa mã nguồn của chúng tôi. Điều này không thường dẫn đến mã lỗi.
Todd Gamblin

35
"Tương đối dễ dàng để tối ưu hóa một chương trình chính xác, nhưng khó hơn nhiều để sửa một chương trình được tối ưu hóa."
gradbot

20
Inge: không chắc bạn đang đi đúng hướng ở đó. Có, C # được triển khai bằng ngôn ngữ khác, nhưng trình biên dịch JIT đang tạo mã máy, vì vậy đó không phải là ngôn ngữ được dịch. Do đó, nó không bị giới hạn bởi việc thực hiện C ++ của nó. Tôi không chắc chắn lý do tại sao bạn nghĩ rằng thêm một số người quản lý vào một cái gì đó vốn đã làm cho nó nhanh hơn.
Martin Probst

202

C # có thể không nhanh hơn, nhưng nó làm cho BẠN / TÔI nhanh hơn. Đó là biện pháp quan trọng nhất cho những gì tôi làm. :)


68
Haha, có một câu nói hay của Larry Wall về chủ đề này. Anh ấy đang nói về perl, nhưng có thể nghĩ đến tất cả các cuộc thảo luận liên quan đến ngôn ngữ và hiệu suất: ".. ngôn ngữ máy tính của Pearl, như Fortran và C, được thiết kế để sử dụng hiệu quả phần cứng máy tính đắt tiền. Ngược lại, Perl được thiết kế để sử dụng hiệu quả các lập trình viên máy tính đắt tiền "
Falaina

60
1. "C # nhanh hơn nhiều so với C ++" 2. "Không thể đúng" 1. "Chắc chắn nó có thể" 2. "Bao nhiêu?" 1. "Thường là 3-4 tháng"
Dmitry S.

2
đối với C ++ thực sự phụ thuộc vào các thư viện mà bạn sử dụng, C # thường không nhanh hơn, .NET là khi bạn nói năng suất
Ion Todirel

Đó là cùng một lý do tại sao bạn có thể sử dụng Python thay vì C để viết một số mã ... nhưng sau khi tạo một số tính toán nặng, bạn có thể cảm thấy sự khác biệt về hiệu suất.
Ch3shire

Điều đó phụ thuộc vào những gì bạn đã quen. Tôi lập trình C ++ nhanh hơn nhiều so với C #. Kiến thức thư viện là một phần lớn trong đó vì bạn không muốn phát minh lại bánh xe cho các nhiệm vụ cơ bản. Vấn đề chính của C / C ++ là quản lý con trỏ được giải quyết khá nhiều với các con trỏ thông minh. Phải nói rằng C ++ nghiêm trọng thiếu một thư viện rộng lớn như .NET và Java cung cấp và điều đó có thể tăng tốc phần lớn sự phát triển. Điều này sẽ không được giải quyết sớm vì những chàng trai std muốn dành thời gian của họ cho việc cải tiến mẫu thay vì mở rộng thư viện.
gast128

87

Đó là năm quả cam nhanh hơn. Hay đúng hơn: không thể có câu trả lời (đúng). C ++ là một ngôn ngữ được biên dịch tĩnh (nhưng sau đó, cũng có tối ưu hóa hướng dẫn hồ sơ), C # được hỗ trợ bởi trình biên dịch JIT. Có rất nhiều sự khác biệt mà những câu hỏi như Hồi có thể trả lời nhanh hơn bao nhiêu, thậm chí không bằng cách đưa ra các mệnh lệnh cường độ.


177
Bạn đã có bằng chứng nào để hỗ trợ cho yêu sách năm quả cam của mình chưa? Tất cả các thí nghiệm của tôi đều chỉ đến 2 quả cam, với sự cải tiến 3 quả xoài khi thực hiện siêu lập trình mẫu.
Alex

42
Tại men, anh ta không kêu la, nó nhanh hơn rất nhiều.
Chris

11
Theo kinh nghiệm của tôi, nó khá là 5,2 quả cam. Nhưng điều này phụ thuộc vào máy đo trái cây bạn sử dụng.
Dio F

4
Cập nhật, chính StackOverflow đã làm rối và xử lý các bình luận không hiệu quả, do đó ít chuối hơn (300 quả chuối tệ hơn mức cần thiết): meta.stackexchange.com/questions/254534/
KeksArmee

87

Tôi sẽ bắt đầu bằng cách không đồng ý với một phần câu trả lời được chấp nhận (và được nâng cao) 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ã JITted sẽ chạy chậm hơn chương trình C ++ (hoặc ngôn ngữ khác không có thời gian chạy) được tối ưu hóa đúng cách bao gồm:

  • tính toán các chu kỳ chi cho mã JITting 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.

  • mọi đường dẫn nóng trong JITter sẽ cạnh tranh với mã của bạn để được hướng dẫn và lưu trữ dữ liệu trong CPU. Chúng tôi biết rằng bộ đệm chiếm ưu thế khi nói đến hiệu suất và các ngôn ngữ bản địa như C ++ không có kiểu tranh chấp này, theo định nghĩa.

  • ngân sách thời gian một thời gian chạy tối ưu được thiết nhiều hơn hạn chế hơn so với các phần mềm tối ưu thời gian biên dịch của (như commenter khác chỉ ra)

Bottom line: Cuối cùng, bạn sẽ gần như chắc chắn có thể tạo ra một thực hiện nhanh hơn trong C ++ hơn bạn có thể trong C # .

Bây giờ, như đã nói, thực sự nhanh hơn bao nhiêu không thể định lượng được, 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ẽ chạy thử nghiệm 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ập vì sự hoàn hảo 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 mà C ++ không có sẵn trong thời gian biên dịch của nó ( tối ưu hóa tĩnh). Ngay cả với điều này, lợi thế vẫn nằm sâu trong tòa án của ứng dụng gốc, 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.

-

Về hiệu suất tương đối, tôi cũng bị làm phiền bởi các số liệu và 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 đồng thời đồng ý, cung cấp một số hỗ trợ cho các tuyên bố tôi đã đưa ra ở trên.

Một phần 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à mong muốn 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ẽ mang lại 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 cung cấp. Hai thay đổi chính mà tôi đã thực hiện đối với mã C ++ là:

1) vectơ đã sử dụng :: reserved ()

2) làm phẳng mảng 2d thành 1d để đạt được vị trí bộ đệm 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): Ban đầu: 124ms, Điền: 165ms

C ++ 14 (Clang v3.8 / C2)

#include <iostream>
#include <vector>

auto TestSuite::ColMajorArray()
{
    constexpr size_t ROWS = 5000;
    constexpr size_t COLS = 9000;

    auto initStart = std::chrono::steady_clock::now();

    auto arr = std::vector<double>();
    arr.reserve(ROWS * COLS);

    auto initFinish = std::chrono::steady_clock::now();
    auto initTime = std::chrono::duration_cast<std::chrono::microseconds>(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<double>(r * c);
        }
    }

    auto fillFinish = std::chrono::steady_clock::now();
    auto fillTime = std::chrono::duration_cast<std::chrono::milliseconds>(fillFinish - fillStart);

    return std::make_pair(initTime, fillTime);
}

Thời gian chạy (Phát hành): Ban đầu: 398 Điên (vâng, đó là micro giây), Điền: 152ms

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 triển khai mảng 1d mang lại Ban đầu: 40ms, Điền: 171ms, Tổng cộng: 211ms ( C ++ vẫn nhanh hơn gần 40% ).

  • Thiết kế và viết mã "nhanh" trong C ++ khó hơn nhiều so với viết mã "thông thường" bằng một trong hai ngôn ngữ.

  • Thật đáng kinh ngạc khi 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 giám sát. Và có rất nhiều cạm bẫy như thế này.

  • Hiệu suất của C # 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 đó là 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 #: https://benchmarkgame.alioth.debian.org/u64q/compare.php?lang=gpp&lang2=csharpcore

Điểm mấu chốt là C ++ cho phép bạn kiểm soát hiệu năng nhiều 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ớ ngăn xếp? Đống? Đa hình động hoặc loại bỏ chi phí thời gian chạy của một vtable với đa hình tĩnh (thông qua các mẫu / CRTP)? Trong C ++, bạn phải ... er, tự mình thực hiện tất cả các lựa chọn này (và hơn thế nữa), để 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, nó đòi hỏi một sự đầu tư sâu hơn để truy cập.


16
@Quonux cảm ơn bạn đã bình luận. Tất nhiên đây không phải là một "chương trình thực sự". Điểm của điểm chuẩn là cấu trúc lại điểm chuẩn C # được cung cấp ở nơi khác trên trang này vì bằng chứng cho thấy mã JITted bằng cách nào đó nhanh hơn bản địa - không phải vậy, và điểm chuẩn có khả năng gây hiểu lầm cho người mới.
U007D

9
@Quonux tại sao bạn phải viết như vậy? Chính những người như bạn khiến tôi không thích stackoverflow.
Markus Knappen Johansson

5
@MarkusKnappenJohansson Tôi đã có một ngày tồi tệ;), tôi cũng chỉ là một con người, đã gỡ bỏ downvote của tôi, nhưng ý kiến ​​của tôi vẫn được áp dụng. Oh xin đừng không thích SO chỉ vì có một số người "ngu ngốc" :). Có một cái tốt đẹp.
Quonux

9
HOÀN TOÀN BỀN VỮNG. Trong phiên bản C ++, bạn chỉ cần dự trữ một phần bộ nhớ (và sau đó ngạc nhiên về cách thao tác đó mất vài giây để thực thi). Trong phiên bản C #, bạn đang tạo 5000 ARRAYS (khởi tạo các đối tượng trong bộ nhớ). C ++ nhanh hơn C # ... nhưng sự khác biệt không ở đâu gần 40% ... ngay bây giờ, nó nằm trong phạm vi <10%. Điều mà ví dụ của bạn minh họa là các lập trình viên nên gắn bó với ngôn ngữ họ chọn (và từ hồ sơ của bạn, rõ ràng bạn là lập trình viên C ++ chuyên nghiệp). Trong C #, bạn có thể thực hiện mảng 2D int[,]... tiếp theo với ví dụ.
nikib3ro

3
Từ những gì tôi có thể nói, mã trong ví dụ C ++ của bạn thực sự chỉ là phân bổ bộ nhớ trước thời hạn. Việc triển khai PROPER C # chỉ đơn giản là viết 'Danh sách <double> arrs = new List <double> (ROWS * COLS)' để phân bổ bộ nhớ cần thiết để lập chỉ mục cho mảng 2 chiều ở định dạng 1 chiều (ví dụ: những gì bạn đã làm trong C ++). Hoàn toàn không có lý do để phân bổ một mảng 2 chiều và làm phẳng nó một cách thủ công - số lượng lặp lớn trong thử nghiệm trước của bạn là nguyên nhân của hiệu suất shitty. Tôi tưởng tượng chi phí vẫn sẽ nhiều hơn trong C #, nhưng không phải là một số lượng đáng kể.
JDSweetBeat

62

Theo kinh nghiệm của tôi (và tôi đã làm việc rất nhiều với cả hai ngôn ngữ), vấn đề chính với C # so với C ++ là mức tiêu thụ bộ nhớ cao và tôi chưa tìm ra cách nào tốt để kiểm soát nó. Đó là mức tiêu thụ bộ nhớ cuối cùng sẽ làm chậm phần mềm .NET.

Một yếu tố khác là trình biên dịch JIT không thể dành quá nhiều thời gian để thực hiện tối ưu hóa nâng cao, bởi vì nó chạy trong thời gian chạy và người dùng cuối sẽ chú ý đến nó nếu mất quá nhiều thời gian. Mặt khác, một trình biên dịch C ++ có tất cả thời gian cần thiết để thực hiện tối ưu hóa tại thời gian biên dịch. Yếu tố này ít quan trọng hơn nhiều so với mức tiêu thụ bộ nhớ, IMHO.


6
Trong một dự án tại nơi làm việc, chúng tôi phải khai thác lượng dữ liệu khổng lồ, bao gồm giữ nhiều GB trong bộ nhớ và thực hiện các phép tính đắt tiền trên tất cả - điều này đòi hỏi phải kiểm soát chính xác tất cả các phân bổ, C ++ là lựa chọn duy nhất. +1 cho C ++. Mặt khác, đó chỉ là một dự án, chúng tôi dành phần lớn thời gian để viết các hệ thống tương tác với các trình giả lập chậm và gỡ lỗi có thể là một cơn ác mộng, vì vậy tôi ước chúng tôi có thể sử dụng ngôn ngữ tối ưu hóa thời gian cho lập trình viên đồ đạc.
Bogatyr

7
@IngeHenriksen: Tôi nhận thức rõ về mẫu Vứt bỏ, nhưng nó không giúp ích gì cho bộ nhớ được quản lý cả.
Nemanja Trifunovic

10
@IngeHenriksen xử lý nó chỉ đảm bảo rằng phương thức Vứt bỏ đã được gọi. Xử lý không bao giờ giải phóng rác bộ nhớ thu thập. Phương thức Vứt bỏ chỉ nhằm mục đích dọn sạch các tài nguyên không được quản lý như xử lý tệp và không liên quan gì đến quản lý bộ nhớ.
doug65536

1
@NemanjaTrifunovic: "Trình biên dịch JIT không thể dành quá nhiều thời gian để thực hiện tối ưu hóa nâng cao". Bạn có thể trích dẫn một số tối ưu hóa không được thực hiện bởi JIT vì chúng sẽ mất quá nhiều thời gian không?
Jon Harrop

5
@ user3800527: Ngay cả khi việc thêm RAM luôn khả thi (và không phải - hãy tưởng tượng Microsoft thêm RAM cho mỗi người dùng MS Office) sẽ không giải quyết được vấn đề. Bộ nhớ được phân cấp và một chương trình C # sẽ có nhiều lỗi nhớ cache hơn so với C ++.
Nemanja Trifunovic

35

Một kịch bản cụ thể trong đó C ++ vẫn chiếm thế thượng phong (và sẽ, trong nhiều năm tới) xảy ra khi các quyết định đa hình có thể được xác định trước tại thời điểm biên dịch.

Nói chung, đóng gói và đưa ra quyết định hoãn lại là một điều tốt vì nó làm cho mã năng động hơn, dễ thích ứng hơn với các yêu cầu thay đổi và dễ sử dụng hơn làm khung. Đây là lý do tại sao lập trình hướng đối tượng trong C # rất hiệu quả và nó có thể được khái quát hóa theo thuật ngữ khái quát hóa. Thật không may, loại khái quát hóa đặc biệt này có chi phí tại thời gian chạy.

Thông thường, chi phí này không đáng kể nhưng có những ứng dụng mà chi phí chung của các cuộc gọi phương thức ảo và tạo đối tượng có thể tạo ra sự khác biệt (đặc biệt là khi các phương thức ảo ngăn chặn các tối ưu hóa khác như gọi nội tuyến). Đây là nơi C ++ có lợi thế rất lớn vì bạn có thể sử dụng các mẫu để đạt được một loại khái quát hóa khác nhau, không ảnh hưởng đến thời gian chạy nhưng không nhất thiết phải ít đa hình hơn OOP. Trong thực tế, tất cả các cơ chế cấu thành OOP có thể được mô hình hóa chỉ bằng các kỹ thuật mẫu và độ phân giải thời gian biên dịch.

Trong những trường hợp như vậy (và phải thừa nhận rằng, chúng thường bị giới hạn trong các miền có vấn đề đặc biệt), C ++ giành chiến thắng trước C # và các ngôn ngữ tương đương.


6
Trên thực tế, các máy ảo Java (và có thể là .NET) có độ dài lớn để tránh việc gửi động. Về cơ bản, nếu có một cách để tránh đa hình, bạn có thể chắc chắn VM của bạn sẽ làm được.
Martin Probst

3
+1 Tôi luôn gặp khó khăn khi giải thích điều này với các đồng nghiệp C # của mình, những người biết ít C ++ theo cách cho phép họ đánh giá cao ý nghĩa này. Bạn đã giải thích nó khá độc đáo.
Roman Starkov

9
@crtvery: bạn đang đặt cược mà không cần các ứng dụng điện toán hiệu năng cao. Xem xét dự báo thời tiết, tin sinh học và mô phỏng số. Hiệu suất dẫn đầu của C ++ trong các lĩnh vực này sẽ không bị thu hẹp, bởi vì không có mã nào khác có thể đạt được hiệu suất tương đương ở cùng mức độ trừu tượng cao.
Konrad Rudolph

5
@Jon Táo và cam. Yêu cầu cụ thể của bạn là C C là các đơn đặt hàng có cường độ nhanh hơn C ++ trong bối cảnh siêu dữ liệu, không phải sử dụng mã được biên dịch trước là các đơn đặt hàng có cường độ nhanh hơn so với mã được giải thích. Trong khi chúng ta đang ở đó, bạn cho rằng việc tạo mã thời gian chạy là chung chung hơn so với việc tạo mã thời gian biên dịch cũng rõ ràng là sai - cả hai đều có điểm mạnh và điểm yếu. Tạo mã thời gian biên dịch sử dụng hệ thống loại để cung cấp an toàn kiểu tĩnh - việc tạo mã thời gian chạy không thể làm điều đó (nó có thể cung cấp an toàn kiểu mạnh, nhưng không phải là an toàn kiểu tĩnh ).
Konrad Rudolph

5
@ user3800527 Tôi nghĩ bạn đang thiếu toàn bộ quan điểm của câu trả lời này. Tất nhiên bạn có thể giải quyết vấn đề này bằng cách phá vỡ đóng gói và thả xuống các cấu trúc cấp thấp - bạn có thể viết lắp ráp bằng (hầu hết) bất kỳ ngôn ngữ nào. Điều làm cho C ++ (gần như) trở nên độc đáo và phù hợp nhất cho lập trình hiệu năng cao, là bạn có thể xây dựng các bản tóm tắt cấp caokhông mất chi phí thời gian chạy. Vì vậy, bạn không cần phải viết mã giống như lắp ráp trong C ++ để có được hiệu năng cao cấp: một văn bản được viết tốt sort(arr, generic_comparer)sẽ hiệu quả như một vòng lặp viết tay trong C ++. Nó sẽ không bao giờ có trong C #.
Konrad Rudolph

20

C ++ (hoặc C cho vấn đề đó) cung cấp cho bạn quyền kiểm soát chi tiết đối với các cấu trúc dữ liệu của bạn. Nếu bạn muốn bit-twiddle bạn có tùy chọn đó. Các ứng dụng Java hoặc .NET được quản lý lớn (OWB, Visual Studio 2005 ) sử dụng cấu trúc dữ liệu nội bộ của các thư viện Java / .NET mang theo hành lý bên mình. Tôi đã thấy các phiên của nhà thiết kế OWB sử dụng hơn 400 MB RAM và BIDS cho thiết kế khối hoặc ETL cũng được đưa vào 100 MB.

Trên một khối lượng công việc có thể dự đoán được (chẳng hạn như hầu hết các điểm chuẩn lặp lại một quy trình nhiều lần), JIT có thể giúp bạn mã được tối ưu hóa đủ tốt để không có sự khác biệt thực tế.

IMO trên các ứng dụng lớn, sự khác biệt không nhiều bằng JIT như các cấu trúc dữ liệu mà chính mã đang sử dụng. Khi một ứng dụng nặng bộ nhớ, bạn sẽ sử dụng bộ nhớ cache kém hiệu quả hơn. Bộ nhớ cache trên CPU hiện đại khá đắt. Trong đó C hoặc C ++ thực sự chiến thắng là nơi bạn có thể tối ưu hóa việc sử dụng cấu trúc dữ liệu của mình để chơi độc đáo với bộ đệm CPU.


19

Đối với đồ họa, lớp Đồ họa C # tiêu chuẩn chậm hơn GDI truy cập thông qua C / C ++. Tôi biết điều này không liên quan gì đến ngôn ngữ, hơn nữa với toàn bộ nền tảng .NET, nhưng Đồ họa là thứ được cung cấp cho nhà phát triển dưới dạng thay thế GDI và hiệu suất của nó rất tệ, tôi thậm chí không dám làm đồ họa với nó.

Chúng tôi có một điểm chuẩn đơn giản mà chúng tôi sử dụng để xem thư viện đồ họa nhanh như thế nào và đó chỉ đơn giản là vẽ các đường ngẫu nhiên trong một cửa sổ. C ++ / GDI vẫn linh hoạt với 10000 dòng trong khi C # / Graphics gặp khó khăn khi thực hiện 1000 trong thời gian thực.


5
Tôi bị thu hút bởi câu trả lời của bạn. Bạn đã kiểm tra điểm chuẩn tương tự với mã và khóa không an toàn và tự vẽ các đường ngẫu nhiên chưa? Bây giờ đó sẽ là một điều thú vị để xem xét.
Pedery

2
@Pedery không có. chỉ sử dụng GDI và .NET.Graphics theo những cách cơ bản nhất. bạn có ý nghĩa gì khi "tự vẽ các đường ngẫu nhiên"?
QBziZ

1
Sau đó, có lẽ bạn nên xem xét để kiểm tra điều này để có được số liệu thực tế hơn về mức độ nhanh chóng của C #. Dưới đây là một tổng quan đẹp về kỹ thuật: bobpowell.net/lockingbits.htm
Pedery

6
Đó không phải là những gì chúng tôi muốn làm, đặt các pixel riêng biệt vào bộ đệm khung. Nếu bạn phải tự thực hiện mọi thứ thì điểm cần có API / Nền tảng để mã hóa là gì? Đối với tôi đây là một cuộc tranh luận. Chúng tôi không bao giờ cần phải đặt các pixel riêng biệt trong bộ đệm khung trong GDI để vẽ các đường và chúng tôi cũng không có kế hoạch thực hiện điều này trong .NET. Theo quan điểm của tôi, chúng tôi đã sử dụng một số liệu thực tế và .NET hóa ra là chậm.
QBziZ

1
Chà, tôi chỉ có một ý tưởng nhỏ là phát hiện blob là gì, nhưng chỉ nêu một thời điểm chứ không chứng minh được gì cả. Bạn đã viết một trong C ++? Trong JavaScript? Và so sánh với những người trong C #? Và bên cạnh đó, tôi không nghĩ rằng phát hiện blob đang sử dụng nhiều nguyên thủy đồ họa. Sửa lỗi cho tôi nếu sai, nhưng tôi đoán đó là thuật toán thống kê thực hiện các thao tác trên pixel.
QBziZ

13

Bộ sưu tập rác là lý do chính khiến Java # CANNOT được sử dụng cho các hệ thống thời gian thực.

  1. Khi nào thì GC sẽ xảy ra?

  2. Làm cái đó mất bao lâu?

Điều này là không xác định.


5
Tôi không phải là một người hâm mộ Java lớn nhưng không có gì nói rằng Java không thể sử dụng một GC thân thiện với thời gian thực.
Zan Lynx

5
Có rất nhiều triển khai GC thời gian thực nếu bạn quan tâm. (GC là một khu vực tràn ngập các tài liệu nghiên cứu)
Arafangion

FWIW, Richard Jones vừa xuất bản một phiên bản cập nhật của cuốn sách thu gom rác của mình bao gồm, trong số những thứ khác, các thiết kế GC thời gian thực hiện đại.
Jon Harrop

11
Đây là một đối số vô nghĩa, Windows (và Linux) không phải là hệ điều hành thời gian thực. Mã C ++ của bạn có thể được hoán đổi cho một số vị trí 18 ms bất cứ lúc nào.
Henk Holterman

2
@HenkHolterman Đúng, nhưng bạn luôn có thể viết một trình nạp khởi động trong cụm, gắn nó vào một bootstrap kernel cho ứng dụng của bạn và thực thi các ứng dụng C ++ của bạn trực tiếp trên phần cứng (trong RT btw). Bạn không thể làm điều này trong C # và bất kỳ nỗ lực nào tôi chỉ thấy bắt chước lắp ráp được biên dịch sẵn trong C # và sử dụng một tấn mã C, khiến cho việc sử dụng C # trở nên ít điểm hơn. Đọc tất cả điều này thật buồn cười, vì C # thực sự vô dụng nếu không có .NET framework.
zackery.fix

11

Chúng tôi đã phải xác định xem C # có thể so sánh với C ++ về hiệu suất hay không và tôi đã viết một số chương trình thử nghiệm cho điều đó (sử dụng Visual Studio 2005 cho cả hai ngôn ngữ). Hóa ra là không có bộ sưu tập rác và chỉ xem xét ngôn ngữ (không phải khung) C # về cơ bản có hiệu suất tương tự như C ++. Cấp phát bộ nhớ trong C # nhanh hơn so với C ++ và C # có một chút yếu tố quyết định khi kích thước dữ liệu được tăng vượt ra ngoài ranh giới dòng bộ đệm. Tuy nhiên, tất cả những thứ này cuối cùng đã được trả tiền và có một chi phí rất lớn dưới dạng các lượt truy cập hiệu suất không xác định cho C # do thu gom rác.


1
Trong C ++, bạn có tùy chọn sử dụng các phương thức phân bổ khác nhau, do đó tùy thuộc vào cách phân bổ bộ nhớ (AOT?) Trong C #, nó có thể được thực hiện theo cách tương tự (nhưng nhanh hơn nhiều) trong C ++.
zackery.fix

5
@ zackery.fix .NET có một lợi thế thú vị trong phân bổ heap, bởi vì nó chỉ phải di chuyển một con trỏ để phân bổ một đối tượng mới. Điều này chỉ khả thi do bộ thu gom rác nén. Tất nhiên bạn có thể làm điều tương tự trong C ++, nhưng C ++ không làm điều đó. Thật buồn cười khi bạn sử dụng cùng một lý lẽ để nói "C # có thể nhưng không, vì vậy đó là rác" và "C ++ thì không, nhưng nó có thể, vì vậy nó thật tuyệt vời" :)
Luaan

9

Như thường lệ, nó phụ thuộc vào ứng dụng. Có những trường hợp C # có thể chậm hơn đáng kể và những trường hợp khác mà C ++ nhanh hơn 5 hoặc 10 lần, đặc biệt trong những trường hợp hoạt động có thể dễ dàng SIMD'd.


Trường hợp tốt nhất cho máy ảo sẽ là biên dịch mã được tạo trong thời gian chạy (ví dụ để khớp với biểu thức chính quy được đọc trong thời gian chạy) vì các chương trình vanilla C ++ được biên dịch tĩnh chỉ có thể sử dụng giải thích vì chúng không có trình biên dịch JIT được tích hợp.
Jon Harrop

Lưu ý từ tương lai: .NET có hỗ trợ cho SIMD và bạn bè kể từ khoảng năm 2014, mặc dù nó không được sử dụng rộng rãi.
Luaan

9

Tôi biết đó không phải là những gì bạn đã hỏi, nhưng C # thường viết nhanh hơn C ++, đây là một phần thưởng lớn trong môi trường thương mại.


2
Tôi muốn nói rằng nó nhanh hơn hầu hết thời gian :)
Bẫy

8

C / C ++ có thể thực hiện tốt hơn rất nhiều trong các chương trình có các mảng lớn hoặc lặp / lặp nặng trên các mảng (ở bất kỳ kích thước nào). Đây là lý do mà đồ họa nói chung nhanh hơn nhiều trong C / C ++, bởi vì các hoạt động mảng nặng làm nền tảng cho hầu hết các hoạt động đồ họa. .NET nổi tiếng là chậm trong các hoạt động lập chỉ mục mảng do tất cả các kiểm tra an toàn và điều này đặc biệt đúng với các mảng đa chiều (và, vâng, các mảng C # hình chữ nhật thậm chí còn chậm hơn các mảng C # lởm chởm).

Phần thưởng của C / C ++ rõ rệt nhất nếu bạn gắn trực tiếp với con trỏ và tránh Boost, std::vectorvà các thùng chứa cấp cao khác, cũng như inlinemọi chức năng nhỏ có thể. Sử dụng mảng trường cũ bất cứ khi nào có thể. Có, bạn sẽ cần nhiều dòng mã hơn để thực hiện điều tương tự như bạn đã làm trong Java hoặc C # khi bạn tránh các thùng chứa cấp cao. Nếu bạn cần một mảng có kích thước động, bạn sẽ chỉ cần nhớ ghép nối của bạn new T[]với một mảng tương ứngdelete[] câu lệnh (hoặc sử dụngstd::unique_ptr) Giá cả cho tốc độ thêm là bạn phải mã cẩn thận hơn. Nhưng đổi lại, bạn có thể tự mình thoát khỏi chi phí bộ nhớ / bộ thu gom rác được quản lý, có thể dễ dàng chiếm 20% hoặc hơn thời gian thực hiện của các chương trình hướng đối tượng nặng nề trong cả Java và .NET, cũng như các chương trình được quản lý lớn chi phí lập chỉ mục mảng bộ nhớ. Các ứng dụng C ++ cũng có thể được hưởng lợi từ một số chuyển đổi trình biên dịch tiện lợi trong một số trường hợp cụ thể.

Tôi là một lập trình viên chuyên gia về C, C ++, Java và C #. Gần đây tôi đã có dịp hiếm hoi để thực hiện chương trình thuật toán chính xác tương tự trong 3 ngôn ngữ sau. Chương trình có rất nhiều phép toán và các phép toán mảng đa chiều. Tôi rất tối ưu hóa điều này trong cả 3 ngôn ngữ. Các kết quả là điển hình cho những gì tôi thường thấy trong các so sánh ít nghiêm ngặt hơn: Java nhanh hơn khoảng 1,3 lần so với C # (hầu hết các JVM được tối ưu hóa hơn CLR) và phiên bản con trỏ thô C ++ có tốc độ nhanh hơn khoảng 2,1 lần so với C #. Lưu ý rằng chương trình C # chỉ sử dụng mã an toàn, theo ý kiến ​​của tôi, bạn cũng có thể mã hóa nó trong C ++ trước khi sử dụng unsafetừ khóa.

Bất cứ ai nghĩ rằng tôi có một cái gì đó chống lại C #, tôi sẽ đóng cửa bằng cách nói rằng C # có lẽ là ngôn ngữ yêu thích của tôi. Đó là ngôn ngữ phát triển logic, trực quan và nhanh nhất mà tôi gặp phải cho đến nay. Tôi làm tất cả các nguyên mẫu của tôi trong C #. Ngôn ngữ C # có nhiều lợi thế nhỏ, tinh tế so với Java (vâng, tôi biết Microsoft đã có cơ hội sửa chữa nhiều thiếu sót của Java bằng cách vào trò chơi muộn và sao chép Java). Có Calendarai nâng cấp lớp Java không? Nếu Microsoft dành nỗ lực thực sự để tối ưu hóa CLR và .NET JITter, C # có thể nghiêm túc tiếp quản. Tôi thực sự ngạc nhiên khi họ chưa có chương trình này, họ đã làm rất nhiều thứ ngay trong ngôn ngữ C #, tại sao không theo dõi nó với tối ưu hóa trình biên dịch nặng? Có lẽ nếu tất cả chúng ta cầu xin.


3
"Bạn sẽ chỉ cần nhớ ghép nối của bạn new T[]với một tương ứng delete[]" - Không, bạn không cần. Có std::unique_ptrđể làm điều đó cho bạn.
emlai

Khi bạn viết một cái gì đó trong đồ họa tại sao lại viết mã an toàn trong c #, bạn đã cân nhắc sử dụng mã không an toàn và so sánh lại chưa?.
dùng3800527

7

> Từ những gì tôi đã nghe ...

Khó khăn của bạn dường như là quyết định xem những gì bạn đã nghe có đáng tin hay không, và khó khăn đó sẽ chỉ được lặp lại khi bạn cố gắng đánh giá các câu trả lời trên trang web này.

Làm thế nào bạn sẽ quyết định nếu những điều mọi người nói ở đây đáng tin hơn hoặc ít hơn những gì bạn nghe ban đầu?

Một cách sẽ là yêu cầu bằng chứng .

Khi ai đó tuyên bố "có một số lĩnh vực trong đó C # chứng tỏ là nhanh hơn C ++", hãy hỏi họ tại sao họ nói vậy , yêu cầu họ chỉ cho bạn các phép đo, yêu cầu họ chỉ cho bạn các chương trình. Đôi khi họ chỉ đơn giản là đã phạm sai lầm. Đôi khi bạn sẽ phát hiện ra rằng họ chỉ đang bày tỏ ý kiến ​​chứ không chia sẻ điều gì đó mà họ có thể cho là đúng.

Thông thường và thông tin sẽ được trộn lẫn trong những gì mọi người yêu cầu, và bạn sẽ phải thử và sắp xếp cái nào. Ví dụ: từ các câu trả lời trong diễn đàn này:

  • "Lấy điểm chuẩn tại http://shootout.alioth.debian.org/ với rất nhiều sự hoài nghi, vì những phần lớn này kiểm tra mã số học, rất có thể không giống với mã của bạn."

    Tự hỏi bản thân xem bạn có thực sự hiểu "những mã số kiểm tra phần lớn này" nghĩa là gì không, và sau đó tự hỏi liệu tác giả đã thực sự cho bạn thấy rằng tuyên bố của anh ta là đúng.

  • "Đó là một thử nghiệm khá vô dụng, vì nó thực sự phụ thuộc vào mức độ tối ưu của các chương trình riêng lẻ; tôi đã quản lý để tăng tốc một số trong số chúng từ 4 - 6 lần trở lên, cho thấy rõ rằng so sánh giữa các chương trình không được tối ưu hóa ngớ ngẩn."

    Hãy tự hỏi liệu tác giả đã thực sự cho bạn thấy rằng anh ta đã xoay sở để "tăng tốc một số trong số họ lên gấp 4 - 6 lần" - đó là một yêu cầu dễ dàng để thực hiện!


Tôi không thể đồng ý với bạn nhiều hơn và đó là lý do tại sao tôi hỏi trong diễn đàn này ... Rốt cuộc, câu trả lời phải ở đâu đó, phải không? :)
Bẫy

1
Đúng. Câu trả lơi con phụ thuộc vao nhiêu thư.".
dùng49117

6

Đối với các vấn đề 'song song hoàn toàn', khi sử dụng Intel TBB và OpenMP trên C ++, tôi đã quan sát thấy hiệu suất tăng gấp 10 lần so với các vấn đề tương tự (toán học thuần túy) được thực hiện với C # và TPL. SIMD là một lĩnh vực mà C # không thể cạnh tranh, nhưng tôi cũng có ấn tượng rằng TPL có một chi phí khá lớn.

Điều đó nói rằng, tôi chỉ sử dụng C ++ cho các nhiệm vụ quan trọng về hiệu năng mà tôi biết tôi sẽ có thể đa luồng và nhận được kết quả nhanh chóng. Đối với mọi thứ khác, C # (và đôi khi F #) là tốt.


5

Đó là một câu hỏi cực kỳ mơ hồ mà không có câu trả lời dứt khoát thực sự.

Ví dụ; Tôi thích chơi các trò chơi 3D được tạo trong C ++ hơn là C #, vì hiệu suất chắc chắn tốt hơn rất nhiều. (Và tôi biết XNA, v.v., nhưng nó không đến gần với thực tế).

Mặt khác, như đã đề cập trước đó; bạn nên phát triển ngôn ngữ cho phép bạn thực hiện những gì bạn muốn một cách nhanh chóng và sau đó nếu cần tối ưu hóa.


4
Bạn có thể kể tên một vài ví dụ? Các trò chơi được viết bằng C # những gì bạn thấy chậm
Karl

1
Ngay cả các ứng dụng ví dụ đi kèm với cài đặt cũng cảm thấy chậm.
David The Man

9
Công cụ thu gom rác là một trách nhiệm rất lớn trong việc tạo ra các trò chơi với C #, vì nó có thể đá bất cứ lúc nào, gây ra sự tạm dừng lớn. Quản lý bộ nhớ rõ ràng kết thúc dễ dàng hơn để phát triển trò chơi.
postfuturist

3
Hầu hết các trò chơi hiện đại đều bị giới hạn GPU. Đối với những trò chơi như vậy, không có vấn đề gì nếu logic (được thực thi trên CPU) chậm hơn 10%, chúng vẫn bị giới hạn bởi GPU chứ không phải CPU. Trình thu gom rác là một vấn đề thực sự, gây ra tình trạng đóng băng ngắn ngẫu nhiên nếu việc phân bổ bộ nhớ không được điều chỉnh tốt.
Michael Entin

2
@postfuturist: Điều đó không đúng trên PC; người thu gom rác thực hiện tốt công việc ra vào Tôi chưa bao giờ gặp phải bất kỳ vấn đề nào với nó. Tuy nhiên, trên Xbox 360 và Zune / Windows-7-Phone, thu gom rác không phải là gần như thông minh như trên máy tính; Tôi chưa bao giờ viết cho một trong hai, nhưng những người đã nói với tôi rằng người thu gom rác là một vấn đề lớn .
BlueRaja - Daniel Pflughoeft

5

Các ngôn ngữ .NET có thể nhanh như mã C ++ hoặc thậm chí nhanh hơn, nhưng mã C ++ sẽ có thông lượng liên tục hơn do thời gian chạy .NET phải tạm dừng cho GC , ngay cả khi nó rất thông minh về việc tạm dừng.

Vì vậy, nếu bạn có một số mã phải chạy nhanh mà không có bất kỳ tạm dừng nào, .NET sẽ giới thiệu độ trễ tại một số điểm , ngay cả khi bạn rất cẩn thận với thời gian chạy GC.


6
-1: Đây thực sự là một huyền thoại. Thứ nhất, độ trễ của C ++ thành ngữ thực sự khủng khiếp và thường tệ hơn nhiều so với .NET vì RAII gây ra các lỗi hủy diệt khi các cấu trúc dữ liệu lớn nằm ngoài phạm vi trong khi các GC hiện đại tăng dần và .NET thậm chí còn đồng thời. Thứ hai, bạn thực sự có thể loại bỏ hoàn toàn các tạm dừng GC trên .NET bằng cách không phân bổ.
Jon Harrop

2
Nếu bạn làm điều này, thì bạn phải từ bỏ bằng cách sử dụng BCL vì hầu hết các phương thức tạo các đối tượng thoáng qua.
Florian Doyon

5
Điều này hoàn toàn đúng, chỉ đến .net 4 thì GC mới được tăng thêm. Chúng tôi có một ứng dụng C # lớn tạm dừng vài giây tại một thời điểm cho GC. Đối với các ứng dụng quan trọng hiệu suất, đây là một kẻ giết người.
Justin

5
Có một lý do tại sao các chương trình có xu hướng đẩy phần cứng có xu hướng sử dụng C ++. Bạn có nhiều kiểm soát điều chỉnh tốt khi bạn cần nó. Hiệu suất chỉ là chìa khóa khi bạn đẩy hệ thống, nếu không thì sử dụng C # hoặc Java để tiết kiệm thời gian của bạn.
VoronoiPotato

4
nếu bạn không thể quản lý hành vi bộ đệm, bạn không thể đánh bại mã c ++ được tối ưu hóa. Một bộ nhớ cache bị mất từ ​​L1 đến bộ nhớ chính có thể làm chậm hoạt động của bạn 100 lần.
DAG

4

Về lý thuyết, đối với ứng dụng loại máy chủ chạy dài, ngôn ngữ được biên dịch JIT có thể trở nên nhiều nhanh hơn so với một đối tác tự nhiên biên soạn. Do ngôn ngữ biên dịch JIT thường được biên dịch đầu tiên sang ngôn ngữ trung gian khá thấp, nên bạn có thể thực hiện rất nhiều tối ưu hóa cấp cao ngay tại thời điểm biên dịch. Lợi thế lớn đến từ việc JIT có thể tiếp tục biên dịch lại các phần mã một cách nhanh chóng khi nó nhận được ngày càng nhiều dữ liệu về cách ứng dụng đang được sử dụng. Nó có thể sắp xếp các đường dẫn mã phổ biến nhất để cho phép dự đoán nhánh thành công thường xuyên nhất có thể. Nó có thể sắp xếp lại các khối mã riêng biệt thường được gọi cùng nhau để giữ cả hai trong bộ đệm. Nó có thể dành nhiều nỗ lực hơn để tối ưu hóa các vòng lặp bên trong.

Tôi nghi ngờ rằng điều này được thực hiện bởi .NET hoặc bất kỳ JRE nào, nhưng nó đã được nghiên cứu trở lại khi tôi còn ở trường đại học, vì vậy không có lý do gì để nghĩ rằng những thứ này có thể sớm được đưa vào thế giới thực .


4

Các ứng dụng yêu cầu truy cập bộ nhớ chuyên sâu, vd. thao tác hình ảnh thường được viết tốt hơn trong môi trường không được quản lý (C ++) so với quản lý (C #). Các vòng lặp bên trong được tối ưu hóa với các tính năng con trỏ dễ dàng hơn để có quyền kiểm soát trong C ++. Trong C #, bạn có thể cần phải sử dụng mã không an toàn để thậm chí đạt được hiệu suất tương tự.


4

Tôi đã thử nghiệm vectortrong C ++ và C # tương đương - Listvà mảng 2d đơn giản.

Tôi đang sử dụng phiên bản Visual C # / C ++ 2010 Express. Cả hai dự án đều là các ứng dụng bảng điều khiển đơn giản, tôi đã thử nghiệm chúng ở chế độ phát hành và gỡ lỗi tiêu chuẩn (không có cài đặt tùy chỉnh). Danh sách C # chạy nhanh hơn trên máy tính của tôi, khởi tạo mảng cũng nhanh hơn trong C #, hoạt động toán học chậm hơn.

Tôi đang sử dụng Intel Core2Duo P8600@2.4GHz, C # - .NET 4.0.

Tôi biết rằng việc triển khai vectơ khác với danh sách C #, nhưng tôi chỉ muốn kiểm tra các bộ sưu tập mà tôi sẽ sử dụng để lưu trữ các đối tượng của mình (và có thể sử dụng trình truy cập chỉ mục).

Tất nhiên bạn cần phải xóa bộ nhớ (giả sử cho mỗi lần sử dụng new), nhưng tôi muốn giữ mã đơn giản.

Kiểm tra vectơ C ++ :

static void TestVector()
{
    clock_t start,finish;
    start=clock();
    vector<vector<double>> myList=vector<vector<double>>();
    int i=0;
    for( i=0; i<500; i++)
    {
        myList.push_back(vector<double>());
        for(int j=0;j<50000;j++)
            myList[i].push_back(j+i);
    }
    finish=clock();
    cout<<(finish-start)<<endl;
    cout<<(double(finish - start)/CLOCKS_PER_SEC);
}

Kiểm tra danh sách C #:

private static void TestVector()
{

    DateTime t1 = System.DateTime.Now;
    List<List<double>> myList = new List<List<double>>();
    int i = 0;
    for (i = 0; i < 500; i++)
    {
        myList.Add(new List<double>());
        for (int j = 0; j < 50000; j++)
            myList[i].Add(j *i);
    }
    DateTime t2 = System.DateTime.Now;
    Console.WriteLine(t2 - t1);
}

C ++ - mảng:

static void TestArray()
{
    cout << "Normal array test:" << endl;
    const int rows = 5000;
    const int columns = 9000;
    clock_t start, finish;

    start = clock();
    double** arr = new double*[rows];
    for (int i = 0; i < rows; i++)
        arr[i] = new double[columns];
    finish = clock();

    cout << (finish - start) << endl;

    start = clock();
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < columns; j++)
            arr[i][j] = i * j;
    finish = clock();

    cout << (finish - start) << endl;
}

C # - mảng:

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 * j;
    t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);

}

Thời gian: (Phát hành / Gỡ lỗi)

C ++

  • Mảng 600.606 ms
  • Mảng 200/270 ms,
  • 1 giây / 13 giây bắt đầu và điền vào.

(Có, 13 giây, tôi luôn gặp vấn đề với danh sách / vectơ ở chế độ gỡ lỗi.)

C #:

  • Mảng 20/20 ms,
  • Điền vào mảng 403/440 ms,
  • Danh sách 710/742 ms init & điền.

1
Tôi muốn thấy trình truy cập chỉ mục trong std :: list. Dù sao, phải mất 37 giây với danh sách, chế độ phát hành. Phát hành mà không cần gỡ lỗi: danh sách 3s, vector 0,3 s. Có lẽ vấn đề hội nghị hoặc sth. Mẫu: nopaste.pl/12fb
Wiory

2
Để đo chính xác hơn, bạn không nên sử dụng System.DateTime.Now, nhưng thay vào đó, lớp Đồng hồ bấm giờ .
Sam

4
Một phần lý do khiến bạn nhận được thời gian điền chậm như vậy cho vectơ trong C ++ là do bạn đang sử dụng Push_back. Điều này đã được hiển thị trên nhiều bài đăng chậm hơn so với sử dụng phương thức hoặc toán tử []. Để sử dụng một trong hai phương pháp đó, bạn cần sử dụng phương pháp thay đổi kích thước hoặc dự trữ. Ngoài ra, lý do khởi tạo của bạn mất quá nhiều thời gian cho trường hợp vectơ c ++ là do bạn buộc một toán tử sao chép hoặc gán [không chắc chắn trong trường hợp này) để khởi tạo vectơ c ++ của bạn. Đối với mảng trong c ++, có một thuật toán sử dụng 2 cuộc gọi mới thay vì 5001 và cũng lặp lại nhanh hơn.
Zachary Kraus

5
Tôi nghĩ bạn đã không làm c ++ theo cách thích hợp. Chỉ cần một cái nhìn và tìm thấy rất nhiều vấn đề. Ví dụ: vectơ <vector <double >> myList = vector <vector <double >> ()
DAG

2
Ồ Không chắc người ta có thể rút ra kết luận gì khi so sánh Danh sách so với mảng có thể thay đổi kích thước, nhưng nếu bạn sẽ sử dụng các vectơ như thế này, bạn sẽ muốn tìm hiểu về dự trữ (), bạn của tôi, dự trữ ().
U007D

3

Vâng, nó phụ thuộc. Nếu mã byte được dịch thành mã máy (và không chỉ JIT) (ý tôi là nếu bạn thực thi chương trình) nếu chương trình của bạn sử dụng nhiều phân bổ / thỏa thuận thì có thể nhanh hơn vì thuật toán GC chỉ cần một lần vượt qua (về mặt lý thuyết) thông qua toàn bộ bộ nhớ một lần, nhưng các cuộc gọi malloc / realloc / C / C ++ miễn phí bình thường gây ra một chi phí trên mỗi cuộc gọi (tổng phí cuộc gọi, chi phí cấu trúc dữ liệu, lỗi bộ nhớ cache;)).

Vì vậy, về mặt lý thuyết là có thể (cũng cho các ngôn ngữ GC khác).

Tôi thực sự không thấy nhược điểm cực kỳ của việc không thể sử dụng siêu lập trình với C # cho hầu hết các ứng dụng, vì hầu hết các lập trình viên đều không sử dụng nó.

Một lợi thế lớn khác là SQL, như "phần mở rộng" LINQ , cung cấp cơ hội cho trình biên dịch tối ưu hóa các cuộc gọi đến cơ sở dữ liệu (nói cách khác, trình biên dịch có thể biên dịch toàn bộ LINQ thành một nhị phân "blob" trong đó các hàm được gọi được đặt trong hoặc để bạn sử dụng được tối ưu hóa, nhưng tôi đang suy đoán ở đây).


1
Bất kỳ nhà phát triển C ++ thích hợp sẽ không gặp phải các vấn đề bạn mô tả. Chỉ những lập trình viên C tồi quyết định tát các lớp trên chương trình của họ và gọi nó là C ++ mới có những vấn đề đó.
Rõ ràng hơn

1
Đối với tình yêu của các vị thần, đây là 8 tuổi, OMFGz
Quonux

vui lòng đưa ra câu trả lời cập nhật hơn
Quonux

2

Tôi cho rằng có những ứng dụng được viết bằng C # chạy nhanh, cũng như có nhiều ứng dụng viết C ++ chạy nhanh hơn (C ++ cũng cũ hơn ... và cũng dùng UNIX ...)
- câu hỏi thực sự là - đó là gì, người dùng là gì và các nhà phát triển đang phàn nàn về ...
Chà, IMHO, trong trường hợp C #, chúng tôi có giao diện người dùng rất thoải mái, hệ thống phân cấp thư viện rất đẹp và toàn bộ hệ thống giao diện của CLI. Trong trường hợp của C ++, chúng tôi có các mẫu, ATL, COM, MFC và toàn bộ shebang của mã alreadyc được viết và chạy như OpenGL, DirectX, v.v ... Các nhà phát triển phàn nàn về các cuộc gọi GC tăng không xác định trong trường hợp C # (có nghĩa là chương trình chạy nhanh và trong một giây - bang! nó bị kẹt).
Để viết mã bằng C # rất đơn giản và nhanh chóng (đừng quên điều đó cũng làm tăng khả năng xảy ra lỗi. Trong trường hợp của C ++, các nhà phát triển phàn nàn về rò rỉ bộ nhớ, - có nghĩa là nghiền nát, các cuộc gọi giữa các DLL, cũng như "DLL hell" - vấn đề với thư viện hỗ trợ và thay thế bởi những thư viện mới hơn ...
Tôi nghĩ rằng bạn sẽ có nhiều kỹ năng hơn trong ngôn ngữ lập trình, chất lượng (và tốc độ) sẽ đặc trưng cho phần mềm của bạn.


2

Tôi sẽ giải thích nó theo cách này: các lập trình viên viết mã nhanh hơn, là những người hiểu biết nhiều hơn về những gì làm cho các máy hiện tại chạy nhanh và tình cờ họ cũng là những người sử dụng một công cụ thích hợp cho phép mức độ chính xác và xác định thấp kỹ thuật tối ưu hóa. Vì những lý do này, những người này là những người sử dụng C / C ++ chứ không phải C #. Tôi sẽ đi xa như nói rằng điều này là một thực tế.


Notch mã hóa minecraft khá nhanh khi xem xét lượng dữ liệu anh ta thao túng. Ngoài ra, anh ta đã mã hóa nó chủ yếu bằng một tay trong một khoảng thời gian tương đối ngắn, một điều gần như không thể có trong C ++. Tôi đồng ý với các kỹ thuật tối ưu hóa mặc dù - nếu bạn có thêm thời gian phát triển gấp 10 lần để mã của bạn chạy nhanh gấp đôi, thì có lẽ nó đáng giá.
Bill K

2

Nếu tôi không nhầm, các mẫu C # được xác định khi chạy. Điều này phải chậm hơn so với các mẫu thời gian biên dịch của C ++.

Và khi bạn thực hiện tất cả các tối ưu hóa thời gian biên dịch khác được đề cập bởi rất nhiều người khác, cũng như sự thiếu an toàn thực sự có nghĩa là tốc độ nhanh hơn ...

Tôi muốn nói C ++ là sự lựa chọn rõ ràng về tốc độ thô và mức tiêu thụ bộ nhớ tối thiểu. Nhưng điều này cũng chuyển sang việc phát triển mã nhiều thời gian hơn và đảm bảo bạn không bị rò rỉ bộ nhớ hoặc gây ra bất kỳ ngoại lệ nào cho con trỏ null.

Bản án:

  • C #: Phát triển nhanh hơn, chạy chậm hơn

  • C ++: Phát triển chậm, chạy nhanh hơn.


1

Nó thực sự phụ thuộc vào những gì bạn đang cố gắng thực hiện trong mã của mình. Tôi đã nghe nói rằng đó chỉ là một thứ của truyền thuyết đô thị rằng có bất kỳ sự khác biệt về hiệu năng giữa VB.NET, C # và C ++ được quản lý. Tuy nhiên, tôi đã tìm thấy, ít nhất là trong các so sánh chuỗi, đã quản lý C ++ đánh bại quần của C #, từ đó đánh bại quần ra khỏi VB.NET.

Tôi hoàn toàn không thực hiện bất kỳ so sánh toàn diện nào về độ phức tạp thuật toán giữa các ngôn ngữ. Tôi cũng chỉ sử dụng các cài đặt mặc định trong mỗi ngôn ngữ. Trong VB.NET, tôi đang sử dụng các cài đặt để yêu cầu khai báo các biến, v.v ... Đây là mã tôi đang sử dụng cho C ++ được quản lý: (Như bạn có thể thấy, mã này khá đơn giản). Tôi đang chạy tương tự trong các ngôn ngữ khác trong Visual Studio 2013 với .NET 4.6.2.

#include "stdafx.h"

using namespace System;
using namespace System::Diagnostics;

bool EqualMe(String^ first, String^ second)
{
    return first->Equals(second);
}
int main(array<String ^> ^args)
{
    Stopwatch^ sw = gcnew Stopwatch();
    sw->Start();
    for (int i = 0; i < 100000; i++)
    {
        EqualMe(L"one", L"two");
    }
    sw->Stop();
    Console::WriteLine(sw->ElapsedTicks);
    return 0;
}

1

Có một số khác biệt chính giữa C # và C ++ về khía cạnh hiệu suất:

  • C # là dựa trên GC / heap. Việc phân bổ và bản thân GC là chi phí hoạt động vì không phải là địa phương của bộ nhớ truy cập
  • Trình tối ưu hóa C ++ đã trở nên rất tốt trong những năm qua. Trình biên dịch JIT không thể đạt được cùng cấp vì chúng chỉ có thời gian biên dịch giới hạn và không thấy phạm vi toàn cầu

Bên cạnh đó năng lực lập trình viên cũng đóng một vai trò. Tôi đã thấy mã C ++ xấu trong đó các lớp được truyền bởi giá trị làm đối số ở mọi nơi. Bạn thực sự có thể làm cho hiệu suất kém hơn trong C ++ nếu bạn không biết những gì bạn đang làm.


0

> Rốt cuộc, câu trả lời phải ở đâu đó, phải không? :)

Ừm ... không.

Như một số câu trả lời đã lưu ý, câu hỏi được chỉ định dưới những cách mời câu hỏi để trả lời chứ không phải câu trả lời. Chỉ thực hiện một cách:

Rồi chương trình nào? Máy nào? HĐH nào? Tập dữ liệu nào?


Tôi hoàn toàn đồng ý. Tôi tự hỏi tại sao mọi người mong đợi một câu trả lời chính xác (63,5%), khi họ hỏi một câu hỏi chung. Tôi không nghĩ rằng không có câu trả lời chung cho loại câu hỏi này.
gọi tôi là Steve

@callmesteve: Tôi biết ý của bạn là gì, nhưng câu cuối cùng của bạn sẽ nghe như tiếng đinh trên bảng phấn đối với bất kỳ lập trình viên nào.
Wouter van Nifterick

1
Điều này không xuất hiện để trả lời câu hỏi và đọc thêm dưới dạng nhận xét hoặc tán gẫu.
TAS

-13

Lấy cảm hứng từ điều này, tôi đã làm một bài kiểm tra nhanh với 60 phần trăm hướng dẫn chung cần thiết trong hầu hết các chương trình.

Đây là mã C #:

for (int i=0; i<1000; i++)
{
    StreamReader str = new StreamReader("file.csv");
    StreamWriter stw = new StreamWriter("examp.csv");
    string strL = "";
    while((strL = str.ReadLine()) != null)
    {
        ArrayList al = new ArrayList();
        string[] strline = strL.Split(',');
        al.AddRange(strline);
        foreach(string str1 in strline)
        {
            stw.Write(str1 + ",");
        }
        stw.Write("\n");
    }
    str.Close();
    stw.Close();
}

Mảng chuỗi và danh sách mảng được sử dụng có chủ đích để bao gồm các hướng dẫn đó.

Đây là mã c ++:

for (int i = 0; i<1000; i++)
{
    std::fstream file("file.csv", ios::in);
    if (!file.is_open())
    {
        std::cout << "File not found!\n";
        return 1;
    }

    ofstream myfile;
    myfile.open ("example.txt");
    std::string csvLine;

    while (std::getline(file, csvLine))
    {
        std::istringstream csvStream(csvLine);
        std::vector csvColumn;
        std::string csvElement;

        while( std::getline(csvStream, csvElement, ‘,’) )
        {
            csvColumn.push_back(csvElement);
        }

        for (std::vector::iterator j = csvColumn.begin(); j != csvColumn.end(); ++j)
        {
            myfile << *j << ", ";
        }

        csvColumn.clear();
        csvElement.clear();
        csvLine.clear();
        myfile << "\n";
    }
    myfile.close();
    file.close();
}

Kích thước tệp đầu vào tôi sử dụng là 40 KB.

Và đây là kết quả -

  • Mã C ++ chạy trong 9 giây.
  • Mã C #: 4 giây !!!

Ồ, nhưng đây là trên Linux ... Với C # chạy trên Mono ... Và C ++ với g ++.

OK, đây là những gì tôi nhận được trên Windows - Visual Studio 2003 :

  • Mã C # chạy trong 9 giây.
  • Mã C ++ - kinh khủng 370 giây !!!

7
Bạn đang sử dụng các cấu trúc dữ liệu và mã thư viện khác nhau ở đó, mặc dù "370 giây" cho thấy điều gì đó thật kinh khủng - bạn có đang chạy nó trong trình gỡ lỗi không? Tôi nghi ngờ rằng hiệu suất của thư viện CSV bạn đang sử dụng thú vị hơn hiệu suất của ngôn ngữ bạn đang sử dụng. Tôi sẽ đặt câu hỏi về việc sử dụng một vectơ trong bối cảnh đó, và những gì tối ưu hóa bạn đã sử dụng. Ngoài ra, người ta biết rộng rãi rằng iostreams (đặc biệt là "myfile << * j <<", ";") chậm hơn nhiều so với các phương pháp ghi vào tệp khác, ít nhất là một số cách triển khai phổ biến.
Arafangion

6
Cuối cùng, bạn đang làm việc nhiều hơn trong phiên bản C ++. (Tại sao bạn xóa csvColumn, csvEuity và csvLines?)
Arafangion

2
Mỗi lần lặp của vòng lặp while sẽ phá hủy và xây dựng lại một std :: istream và std :: vector và std :: string. Phần thân while vượt ra khỏi phạm vi mỗi lần lặp, tất cả các biến trong phạm vi while sẽ bị hủy và xây dựng trên mỗi lần lặp.
doug65536

1
từ vẻ ngoài của việc đọc mã c ++ của bạn, bạn đang cố sao chép từ tệp này sang tệp khác. Thay vì sử dụng các tương tác phức tạp giữa các luồng tệp, chuỗi, vectơ và luồng chuỗi, bạn có thể vừa sao chép luồng tệp đầu vào vào luồng tệp đầu ra. Điều này sẽ tiết kiệm rất nhiều thời gian và bộ nhớ.
Zachary Kraus

2
để thực hiện các bài kiểm tra tốc độ, kiểm tra mọi thứ trong memmory không vào đĩa IO, trừ khi thử nghiệm của bạn trên ổ SSD mới nhất và dành riêng cho ứng dụng hiệu suất của bạn. Khi máy tính liên tục ghi vào đĩa, ngay cả khi bạn không chạm vào bàn phím.
dùng3800527
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.