Tại sao C quá nhanh và tại sao các ngôn ngữ khác lại nhanh hay nhanh hơn? [đóng cửa]


208

Khi nghe podcast StackOverflow, jab tiếp tục phát hiện ra rằng "lập trình viên thực sự" viết bằng C và C nhanh hơn rất nhiều vì nó "gần với máy". Rời khỏi khẳng định trước đây cho một bài đăng khác, điều gì đặc biệt ở C cho phép nó nhanh hơn các ngôn ngữ khác? Hoặc đặt một cách khác: những gì để ngăn các ngôn ngữ khác có thể biên dịch thành nhị phân chạy nhanh như C?


6
Bạn có thể liệt kê chương trình cụ thể nói về điều này? Tôi rất thích nghe nó.
Giovanni Galbo

2
Tôi thực sự ngạc nhiên về câu hỏi này được trả lời tệ như thế nào (hầu hết các câu trả lời đều bỏ qua sự khác biệt cơ bản giữa ngôn ngữ được biên dịch và phiên dịch, v.v., tôi biết về JIT yada yada yada) và có bao nhiêu người đang đảm nhận vị trí 'bảo vệ' ngôn ngữ yêu thích của họ (cậu bé FORTRAN cần uống một viên thuốc).
Tim Ring

Đừng quên ngôn ngữ lắp ráp. Không có gì nhanh hơn hoặc gọn hơn so với exes lắp ráp lắp ráp. Hội là gần như nhị phân thuần túy, vì vậy nó không thiên vị ngôn ngữ nhanh nhất.
KKZiomek

3
C là nhanh nhất vì đó là tốc độ ánh sáng và tính tương đối?
Gặp Taraviya

Tất nhiên là sai khi C là ngôn ngữ chương trình nhanh nhất. Không có ngôn ngữ chương trình thuộc bất kỳ loại nào đến gần tốc độ của FORTH. FORTH được sử dụng để kích hoạt bom hạt nhân, nó là ngôn ngữ chương trình trên hầu hết các vệ tinh, ngôn ngữ chương trình chính trong Trạm vũ trụ quốc tế và cả ở CERN và tại ITER. Tôi đã so sánh tốc độ giữa Microsoft C (các phiên bản khác nhau) và FORTH. YAWN đến C ...
Scoobeedo Cool 18/12/17

Câu trả lời:


200

Không có gì đặc biệt về C. Đó là một trong những lý do tại sao nó nhanh.

Các ngôn ngữ mới hơn có hỗ trợ thu gom rác , gõ động và các phương tiện khác giúp lập trình viên dễ dàng viết chương trình hơn.

Điều thú vị là, có thêm chi phí xử lý sẽ làm giảm hiệu suất của ứng dụng. C không có bất kỳ thứ gì trong đó, điều đó có nghĩa là không có phí, nhưng điều đó có nghĩa là lập trình viên cần có khả năng phân bổ bộ nhớ và giải phóng chúng để tránh rò rỉ bộ nhớ và phải xử lý việc gõ biến tĩnh.

Điều đó nói rằng, nhiều ngôn ngữ và nền tảng, chẳng hạn như Java (với Máy ảo Java ) và .NET (với Thời gian chạy ngôn ngữ chung) đã cải thiện hiệu suất qua nhiều năm với những tiến bộ như biên dịch đúng lúc tạo ra mã máy gốc từ mã byte để đạt được hiệu suất cao hơn.


3
thu gom rác có thể nhanh hơn quản lý bộ nhớ thủ công (đối với các chương trình ngắn hạn và / hoặc nhiều bộ nhớ). GC cho phép phân bổ đơn giản và nhanh chóng, và chương trình không dành thời gian giải quyết mọi thứ.
Kornel

2
Các chương trình C thường phân bổ và phân bổ bộ nhớ trên cơ sở khi cần thiết. Điều này là không hiệu quả. Một VM tốt sẽ phân bổ và phân bổ thành nhiều phần lớn, mang lại hiệu quả lớn trong hiệu suất trong nhiều trường hợp.
skaffman

60
Không có gì ngăn cản một chương trình C thực hiện phân bổ rác và phân loại rác tương tự, ngoài việc "cứng".
ephemient

Nói rất hay, nhưng như Rob Allen đã nói, C cũng cung cấp ít trừu tượng hơn Java hoặc .NET, dẫn đến việc dịch ít hơn (điều này không đúng trong ngày hôm nay do biên dịch đúng lúc (JIT) như bạn đã nói)
Gab Royer

5
porneL, quản lý thủ công và phân bổ hợp lý sẽ luôn vượt trội hơn bất kỳ hệ thống GC nào khi được sử dụng đúng cách và được chú ý nhiều, bạn có kiến ​​thức tuyệt đối về mô hình sử dụng của mình, GC không, cộng với các hệ thống GC thêm chi phí
Ion Todirel

89

Có một sự đánh đổi mà các nhà thiết kế C đã thực hiện. Điều đó có nghĩa là, họ đã đưa ra quyết định đưa tốc độ lên trên mức an toàn. C sẽ không

  • Kiểm tra giới hạn chỉ số mảng
  • Kiểm tra các giá trị biến chưa được khởi tạo
  • Kiểm tra rò rỉ bộ nhớ
  • Kiểm tra độ chính xác của con trỏ null

Khi bạn lập chỉ mục vào một mảng, trong Java, nó sẽ thực hiện một số cuộc gọi phương thức trong máy ảo, kiểm tra ràng buộc và kiểm tra độ tỉnh táo khác. Điều đó là hợp lệ và hoàn toàn tốt , bởi vì nó thêm an toàn khi đến hạn. Nhưng trong C, ngay cả những thứ tầm thường cũng không được an toàn. Ví dụ: C không yêu cầu memcpy để kiểm tra xem các vùng có sao chép trùng lặp hay không. Nó không được thiết kế như một ngôn ngữ để lập trình một ứng dụng kinh doanh lớn.

Nhưng những quyết định thiết kế là không lỗi trong ngôn ngữ C . Chúng là theo thiết kế, vì nó cho phép các trình biên dịch và người viết thư viện lấy mọi bit hiệu năng ra khỏi máy tính. Đây là tinh thần của C làm thế nào tài liệu C Cation giải thích nó:

Mã C có thể không di động. Mặc dù nó cố gắng tạo cơ hội cho các lập trình viên viết các chương trình di động thực sự, Ủy ban không muốn buộc các lập trình viên phải viết một cách hợp lý, để ngăn chặn việc sử dụng C như một 'trình biên dịch cấp cao' ': khả năng viết cụ thể của máy mã là một trong những điểm mạnh của C.

Giữ tinh thần của C. Ủy ban giữ mục tiêu chính là giữ gìn tinh thần truyền thống của C. Có nhiều khía cạnh của tinh thần C, nhưng bản chất là một tình cảm cộng đồng của các nguyên tắc cơ bản mà ngôn ngữ C dựa trên. Một số khía cạnh của tinh thần C có thể được tóm tắt trong các cụm từ như

  • Tin tưởng lập trình viên.
  • Đừng ngăn cản lập trình viên làm những gì cần phải làm.
  • Giữ ngôn ngữ nhỏ và đơn giản.
  • Chỉ cung cấp một cách để thực hiện một thao tác.
  • Làm cho nó nhanh, ngay cả khi nó không được đảm bảo là di động.

Câu tục ngữ cuối cùng cần một lời giải thích nhỏ. Tiềm năng tạo mã hiệu quả là một trong những thế mạnh quan trọng nhất của C. Để giúp đảm bảo rằng không có vụ nổ mã nào xảy ra đối với hoạt động rất đơn giản, nhiều thao tác được xác định là cách phần cứng của máy mục tiêu thực hiện thay vì một quy tắc trừu tượng chung. Một ví dụ về sự sẵn sàng sống với những gì máy có thể được nhìn thấy trong các quy tắc chi phối việc mở rộng các đối tượng char để sử dụng trong các biểu thức: việc các giá trị của các đối tượng char mở rộng thành số lượng có dấu hoặc không dấu thường phụ thuộc vào hoạt động byte nào nhiều hơn hiệu quả trên máy mục tiêu.


51
C không kiểm tra deref con trỏ null bằng cách đâm dữ dội :-). Nó cũng thỉnh thoảng kiểm tra các chỉ mục mảng ngoài phạm vi và các biến chưa được khởi tạo bằng cách làm hỏng các khung và dữ liệu ngăn xếp của bạn. Thật không may, nó kiểm tra những lúc này.
paxdiablo

18
Tôi sẽ không nói rằng C không an toàn, nghe giống như những gì bạn đang ám chỉ. Nó cho rằng bạn không phải là một thằng ngốc. Nếu bạn chĩa súng xuống và tự bắn vào chân mình, C sẽ vui vẻ bắt buộc và để bạn làm điều đó bởi vì nó cho rằng bạn thông minh hơn nó. Đó không hẳn là một điều xấu.
Bob Bolog

19
@Bob: Chính xác. Nói C không an toàn vì nó cho phép bạn làm những việc nguy hiểm cũng giống như nói xe không an toàn vì nó sẽ cho phép bạn lái xe khỏi một vách đá. C an toàn như người lái xe (nhưng có rất nhiều tài xế không an toàn ngoài kia).
Robert Gamble

5
Bob, làm cho các lỗi như tràn bộ đệm không có nghĩa là bạn là một thằng ngốc. Nó chỉ có nghĩa là bạn vẫn là con người. Tôi nhận ra rằng C và C ++ không tệ (tôi rất giống họ).
Julian Schaub - litb

4
@ JohannesSchaub-litb C hoàn hảo cho lập trình ứng dụng quy mô lớn. Nếu ai đó cảm thấy khó khăn để làm cho các dự án lớn hơn một thế giới xin chào, thì vấn đề là ở lập trình viên, không phải với ngôn ngữ ...

75

Nếu bạn dành một tháng để xây dựng một cái gì đó trong C chạy trong 0,05 giây và tôi dành một ngày để viết điều tương tự bằng Java và nó chạy trong 0,10 giây, thì C có thực sự nhanh hơn không?

Nhưng để trả lời câu hỏi của bạn, được viết tốt mã C thường sẽ chạy nhanh hơn mã được viết tốt bằng các ngôn ngữ khác vì một phần của việc viết mã C "tốt" bao gồm thực hiện tối ưu hóa thủ công ở cấp độ gần máy.

Mặc dù các trình biên dịch thực sự rất thông minh, nhưng chúng chưa thể sáng tạo ra mã cạnh tranh với các thuật toán được tạo khối bằng tay (giả sử "bàn tay" thuộc về một lập trình viên giỏi C).

Biên tập:

Rất nhiều bình luận dọc theo dòng chữ "Tôi viết bằng C và tôi không nghĩ về việc tối ưu hóa."

Nhưng để lấy một ví dụ cụ thể từ bài đăng này :

Trong Delphi tôi có thể viết điều này:

function RemoveAllAFromB(a, b: string): string;
var
  before, after :string;
begin
  Result := b;
  if 0 < Pos(a,b) then begin
    before := Copy(b,1,Pos(a,b)-Length(a));
    after := Copy(b,Pos(a,b)+Length(a),Length(b));
    Result := before + after;
    Result := RemoveAllAFromB(a,Result);  //recursive
  end;
end;

và trong CI viết điều này:

char *s1, *s2, *result; /* original strings and the result string */
int len1, len2; /* lengths of the strings */
for (i = 0; i < len1; i++) {
   for (j = 0; j < len2; j++) {
     if (s1[i] == s2[j]) {
       break;
     }
   }
   if (j == len2) {  /* s1[i] is not found in s2 */
     *result = s1[i]; 
     result++; /* assuming your result array is long enough */
   }
}

Nhưng có bao nhiêu tối ưu hóa trong phiên bản C? Chúng tôi đưa ra rất nhiều quyết định về việc triển khai mà tôi không nghĩ tới trong phiên bản Delphi. Làm thế nào là một chuỗi thực hiện? Ở Delphi tôi không thấy nó. Trong C, tôi đã quyết định nó sẽ là một con trỏ tới một mảng các số nguyên ASCII, mà chúng ta gọi là ký tự. Trong C, chúng tôi kiểm tra sự tồn tại của nhân vật một lần. Trong Delphi, tôi sử dụng Pos.

Và đây chỉ là một ví dụ nhỏ. Trong một chương trình lớn, một lập trình viên C phải đưa ra các loại quyết định cấp thấp này với mỗi vài dòng mã. Nó thêm vào một thực thi thủ công, tối ưu hóa bằng tay.


45
Mặc dù công bằng mà nói, sẽ không có nhiều thứ sẽ mất một tháng trong C mà chỉ mất một ngày trong Java mà chỉ mất 0,05 giây để thực thi (tức là chương trình nhỏ).
dreamlax

12
Tôi đã lập trình bằng C trong nhiều năm và hầu như không bao giờ phải thực hiện bất kỳ loại tối ưu hóa nào mà bạn gợi ý. Tôi đã chuyển một số chương trình sang C (chủ yếu từ Perl) và thường thấy tốc độ tăng gấp 10 lần và giảm đáng kể việc sử dụng bộ nhớ mà không có bất kỳ tối ưu hóa mã hóa bằng tay nào.
Robert Gamble

1
Tất nhiên, có một số thứ có thể mất nhiều thời gian hơn để lập trình trong C do thiếu các phương tiện hiện có nên đó là sự đánh đổi giữa hiệu suất máy tính và hiệu suất lập trình viên (trong số những thứ khác), đó là lý do tại sao chúng ta không lập trình mọi thứ trong C.
Robert Gamble

4
Tôi đã tạo các chương trình C ++ xử lý hàng ngàn dòng dữ liệu trong thời gian ngắn hơn sau đó các chương trình Java hoặc .NET có thể khởi động. Đó là một trong những nỗi thất vọng mà tôi có với các ngôn ngữ hiện đại hơn. C là tuyệt vời cho các chương trình nạc cần yêu cầu thời gian chạy tối thiểu. PowerBasic cũng tuyệt vời cho điều đó.
bruceatk

35
Bạn đang nói rằng một chương trình mất một tháng bằng C và nhanh gấp đôi so với một chương trình được viết bằng Java mà chỉ mất một ngày để viết không đáng giá? Điều gì xảy ra nếu chương trình đó cần chạy hơn 500.000.000 lần mỗi ngày? Nhanh gấp đôi là vô cùng quan trọng. Nếu nó chạy trên hàng ngàn hoặc hàng triệu CPU, tiết kiệm chi phí của tháng phát triển thêm để đạt được hiệu năng gấp đôi sẽ là rất lớn. Về cơ bản, bạn phải biết / hiểu quy mô triển khai của mình trước khi chọn nền tảng phát triển.
nicerobot

49

Tôi không nhìn thấy nó rồi, vì vậy tôi sẽ nói nó: C có xu hướng nhanh hơn bởi vì hầu như tất cả mọi thứ khác được viết bằng C .

Java được xây dựng trên C, Python được xây dựng trên C (hoặc Java hoặc .NET, v.v.), Perl là, v.v. Hệ điều hành được viết bằng C, các máy ảo được viết bằng C, các trình biên dịch được viết bằng C, thông dịch viên được viết bằng C. Một số điều vẫn được viết bằng ngôn ngữ hội, có xu hướng thậm chí còn nhanh hơn. Ngày càng có nhiều thứ được viết bằng thứ khác, chính nó được viết bằng C.

Mỗi câu lệnh mà bạn viết bằng các ngôn ngữ khác (không phải hội) thường được triển khai bên dưới như một số câu lệnh trong C, được biên dịch thành mã máy gốc. Vì các ngôn ngữ khác có xu hướng tồn tại để đạt được mức độ trừu tượng cao hơn C, các câu lệnh bổ sung được yêu cầu trong C có xu hướng tập trung vào việc thêm an toàn, thêm độ phức tạp và cung cấp xử lý lỗi. Đó thường là những điều tốt, nhưng chúng có chi phí , và tên của nó là tốc độkích thước .

Cá nhân, tôi đã viết bằng hàng chục ngôn ngữ bao trùm hầu hết các phổ có sẵn và cá nhân tôi đã tìm kiếm điều kỳ diệu mà bạn gợi ý:

Làm thế nào tôi có thể có bánh của tôi và ăn nó? Làm cách nào tôi có thể chơi với các bản tóm tắt cấp cao bằng ngôn ngữ yêu thích của mình, sau đó thả xuống mức độ khó chịu của C cho tốc độ?

Sau một vài năm nghiên cứu, câu trả lời của tôi là Python (trên C). Bạn có thể muốn cho nó một cái nhìn. Nhân tiện, bạn cũng có thể thả xuống hội từ Python (với một số trợ giúp nhỏ từ một thư viện đặc biệt).

Mặt khác, mã xấu có thể được viết bằng bất kỳ ngôn ngữ nào . Do đó, mã C (hoặc hội) không tự động nhanh hơn. Tương tự như vậy, một số thủ thuật tối ưu hóa có thể mang lại các phần mã ngôn ngữ cấp cao gần với mức hiệu năng của C. Nhưng, đối với hầu hết các ứng dụng, chương trình của bạn dành phần lớn thời gian chờ đợi cho mọi người hoặc phần cứng, vì vậy sự khác biệt thực sự không quan trọng.

Thưởng thức.


10
Điều này không thực sự áp dụng cho các ngôn ngữ do JIT biên soạn. Nó không giống như C # của tôi đang được biên dịch sang IL được dịch sang C được biên dịch thành mã máy. Không, IL được biên soạn JIT - và ngôn ngữ triển khai của JIT là không liên quan tại thời điểm đó. Nó chỉ sản xuất mã máy.
Jon Skeet

3
Chúa cấm tôi nên hỏi Jon Skeet huyền thoại, nhưng dường như hoàn toàn có liên quan rằng mã máy được sản xuất là dành cho C # thay vì C, vì vậy nó là "cấp cao hơn", có nhiều chức năng hơn, có kiểm tra an toàn, v.v. do đó, chậm hơn so với "tương đương" C.
Rob Williams

3
@Jon: Tôi đã định nói điều gì đó tương tự nhưng điểm thực sự có phần hợp lệ vì rất nhiều thành phần cốt lõi của thư viện .NET thực sự được viết bằng C và do đó có giới hạn tốc độ của C. Sẽ rất thú vị để xem điều này sẽ thay đổi như thế nào trong tương lai.
Konrad Rudolph

1
Điều này có vẻ sai, xung quanh, trình biên dịch / thông dịch / vms ngôn ngữ khác thường xuyên nhưng không phải lúc nào cũng được viết bằng c (hoặc ít nhất là cho lớp thấp nhất) vì c khá nhanh (và trong nhiều trường hợp là nhanh nhất).
Roman A. Taycher

2
Câu trả lời này không đúng. Như đã chỉ ra ở trên, nó không áp dụng cho các ngôn ngữ JIT, nhưng nó cũng không áp dụng cho các ngôn ngữ có trình biên dịch riêng của chúng (điều này, nếu nỗ lực phi thường được đưa vào chúng, có thể tạo mã nhanh hơn trình biên dịch C hiện đại). Loại ngôn ngữ duy nhất còn lại là ngôn ngữ thông dịch và những ngôn ngữ đó không chậm hơn C chỉ vì chúng được viết bằng C, nhưng vì chi phí phiên dịch, bất kể bạn cắt nó như thế nào và ngay cả khi trình thông dịch được viết trong cụm , là rất lớn.
Điểm_Under 17/1/2016

38

Có rất nhiều câu hỏi trong đó - chủ yếu là những câu hỏi mà tôi không đủ điều kiện để trả lời. Nhưng đối với điều cuối cùng này:

Điều gì để ngăn các ngôn ngữ khác không thể biên dịch thành nhị phân chạy nhanh như C?

Trong một từ, Trừu tượng.

C chỉ là một hoặc 2 mức độ trừu tượng cách xa ngôn ngữ máy. Các ngôn ngữ Java và .Net ở mức tối thiểu 3 mức độ trừu tượng khỏi trình biên dịch chương trình. Tôi không chắc chắn về Python và Ruby.

Thông thường, càng nhiều đồ chơi lập trình (kiểu dữ liệu phức tạp, v.v.), bạn càng đến từ ngôn ngữ máy và càng phải thực hiện nhiều bản dịch.

Tôi ra khỏi đây và ở đó nhưng đó là ý chính cơ bản.

Cập nhật ------- Có một số bình luận tốt về bài đăng này với nhiều chi tiết hơn.


3
Về mặt kỹ thuật, Java và .Net được trừu tượng hóa hoàn toàn khỏi ngôn ngữ máy của máy họ chạy. Họ chạy trong VM. Ngay cả với JIT, mã gốc phải được mát xa ồ ạt để có được thứ gì đó giống với mã máy gốc.
jmucchiello

1
Mã .net không chạy trong VM. Nó chạy như hướng dẫn riêng trên bất kỳ nền tảng bộ xử lý nào mà nó đang chạy (32 bit x86, 64 bit x86 hoặc IA64).
Robert C. Barth

11
@Robert: .net không sử dụng VM. Mã .net được biên dịch thành mã byte được thực thi bởi VM. VM chuyển đổi mã byte thành các lệnh gốc trong thời gian chạy.
Robert Gamble

3
Điều rất quan trọng cần lưu ý là Java và các tóm tắt ngôn ngữ OO khác đã ảnh hưởng đến các tập lệnh của bộ xử lý. Các bộ xử lý mới hơn có các hướng dẫn làm cho Java chạy nhanh hơn nếu java VM biết về các tối ưu hóa này và sử dụng chúng. Nó không lớn, nhưng nó hữu ích.
Adam Davis


35

Không quá nhiều khi C nhanh vì mô hình chi phí của C là minh bạch . Nếu một chương trình C chậm, thì nó chậm theo một cách rõ ràng: bằng cách thực hiện rất nhiều câu lệnh. So với chi phí hoạt động trong C, hoạt động cấp cao trên các đối tượng (đặc biệt là phản xạ) hoặc chuỗi có thể có chi phí không rõ ràng.

Hai ngôn ngữ thường biên dịch thành nhị phân nhanh như C là ML chuẩn (sử dụng trình biên dịch MLton ) và Objective Caml . Nếu bạn kiểm tra trò chơi điểm chuẩn, bạn sẽ thấy rằng đối với một số điểm chuẩn, như cây nhị phân, phiên bản OCaml nhanh hơn C. (Tôi không tìm thấy bất kỳ mục MLton nào.) Nhưng đừng quá coi trọng việc bắn súng; như một trò chơi, kết quả thường phản ánh mức độ nỗ lực của mọi người trong việc điều chỉnh mã.


Có thể viết mã không rõ ràng đắt tiền bằng bất kỳ ngôn ngữ nào. Chỉ là trong một số ngôn ngữ, bạn phải viết một biến thể bên trong của Lisp hoặc Forth đầu tiên
Donal Fellows

Ngoài ra Rust phù hợp với C trong điểm chuẩn.
stark

18

C không phải lúc nào cũng nhanh hơn.

C chậm hơn, ví dụ Modern Fortran.

C thường chậm hơn Java đối với một số thứ. (Đặc biệt là sau khi trình biên dịch JIT có mã của bạn)

C cho phép khử răng cưa xảy ra, điều đó có nghĩa là một số tối ưu hóa tốt là không thể. Đặc biệt khi bạn có nhiều đơn vị thực thi, điều này gây ra các quầy tìm nạp dữ liệu. Ow.

Giả định rằng công việc số học con trỏ thực sự gây ra hiệu năng cồng kềnh chậm trên một số họ CPU (đặc biệt là PIC!) Nó được sử dụng để hút số lớn trên x86 được phân đoạn.

Về cơ bản, khi bạn nhận được một đơn vị vectơ hoặc trình biên dịch song song, C hôi thối và Fortran hiện đại chạy nhanh hơn.

Các thủ thuật lập trình C như thunking (sửa đổi thực thi khi đang di chuyển) gây ra các quầy hàng tìm nạp CPU.

Bạn có được sự trôi dạt?

Và người bạn tốt của chúng tôi, x86, thực hiện một tập lệnh mà ngày nay có ít mối quan hệ với kiến ​​trúc CPU thực tế. Thanh ghi bóng, tối ưu hóa lưu trữ tải, tất cả trong CPU. Vậy C gần với kim loại ảo. Kim loại thật, Intel không cho bạn thấy. (Về mặt lịch sử, CPU của VLIW hơi ồn ào, có lẽ điều đó không tệ lắm.)

Nếu bạn lập trình trong C trên DSP hiệu suất cao (có thể là TI DSP?), Trình biên dịch phải thực hiện một số công cụ khó khăn để hủy đăng ký C qua nhiều đơn vị thực thi song song. Vì vậy, trong trường hợp đó C không gần với kim loại, nhưng nó gần với trình biên dịch, sẽ thực hiện tối ưu hóa toàn bộ chương trình. Kỳ dị.

Và cuối cùng, một số CPU (www.ajile.com) chạy mã byte Java trong phần cứng. C sẽ sử dụng PITA trên CPU đó.


1
Lần cuối cùng thunking được viết là khi nào? Modern x86 là một giao diện cho thiết kế chủ yếu là RISC, nhưng điều đó ít liên quan đến VLIW ...
Calyth

7
Phần lớn bài viết của bạn bỏ qua sự tồn tại của C99. Ngoài ra, nhiều trình biên dịch C / C ++ cung cấp từ khóa hạn chế C99 (đảm bảo không có bí danh con trỏ) như một phần mở rộng.
Evan Teran

Tôi giả định rằng tất cả mọi người đang theo dõi / chuyển sang theo dõi top 25 của CWE / Sans và tránh tạo ra các thiết kế mới trong C. Vì vậy, không có trường C xanh, rất ít để không có C99.
Tim Williscroft

2
Bạn có thể đưa ra ví dụ khi c chậm hơn Fortenberry hiện đại?
Adam

Tôi không chắc đã có lúc các trình biên dịch C cạnh tranh rất tốt với các trình biên dịch Fortran tốt nhất. Tất nhiên, có rất nhiều mã bạn sẽ không muốn viết trong FORTRAN 77 (huống chi là 66), nhưng các tiêu chuẩn Fortran gần đây đã ngày càng dễ chịu hơn.
tfb

11

Điều gì để ngăn các ngôn ngữ khác không thể biên dịch thành nhị phân chạy nhanh như C?

Không có gì. Các ngôn ngữ hiện đại như ngôn ngữ Java hoặc .NET được định hướng nhiều hơn về năng suất của lập trình viên thay vì hiệu suất. Phần cứng là ngày nay giá rẻ. Ngoài ra, việc biên dịch thành biểu diễn trung gian mang lại rất nhiều phần thưởng như bảo mật, tính di động, v.v. .NET CLR có thể tận dụng các phần cứng khác nhau - ví dụ bạn không cần phải tối ưu hóa / biên dịch lại chương trình theo cách thủ công để sử dụng bộ lệnh SSE.


tôi sẽ tranh luận về tính di động ở đây. Nếu bạn muốn mã di động thực sự, bạn sẽ viết nó bằng C và không phải bằng bất kỳ ngôn ngữ nào khác. Chúng tôi có một mã chạy trên khoảng 25 hệ điều hành. Bắt đầu từ dos và threadX và hoàn thiện trên Linux / XP cho tôi thấy một ngôn ngữ khác có thể làm điều đó :)
Ilya

1
@Ilya tôi không đồng ý. Thật dễ dàng để viết mã không di động trong C. Hãy nhìn xem mức độ đau đớn của một số người chuyển sang 64-bit. Các langau byte có thể hoạt động trên nền tảng nếu bạn có trình thông dịch mã byte đúng.
Calyth

1
@IIya, mã C di động là một ngoại lệ thay vì quy tắc, tôi đã chuyển mã C giữa các nền tảng phần cứng / phần mềm khác nhau và biết rằng đó là một cơn ác mộng.
aku

Ngay cả đối với PC từ nó không phải là trường hợp. Nhìn vào thực tế hầu hết các ứng dụng đa nền tảng được viết bằng c / c ++, một chút trong java. Đối với phát triển cấp thấp nhúng, không có trường hợp khác. C là ngôn ngữ di động nhất trên thực tế.
Ilya

@aku -> PORTING mã xấu có thể là thảm họa tôi đồng ý. Viết mã di động trong ADVANCE - C là một lựa chọn tốt nhất. Tôi có thể nói C ++ là một tùy chọn nhưng đi đến nền tảng nhúng, bạn sẽ luôn tìm thấy trình biên dịch C phong nha, đối với c ++ bạn có thể tự tìm thấy mình mà không cần trình biên dịch.
Ilya

8

Các yếu tố chính là ngôn ngữ được nhập tĩnh và được biên dịch thành mã máy. Ngoài ra, vì là ngôn ngữ cấp thấp, nên nó thường không làm bất cứ điều gì bạn không nói với nó.

Đây là một số yếu tố khác mà đến với tâm trí.

  • Các biến không được tự động khởi tạo
  • Không có giới hạn kiểm tra trên mảng
  • Thao tác con trỏ không được kiểm tra
  • Không kiểm tra tràn số nguyên
  • Các biến được nhập tĩnh
  • Các lệnh gọi hàm là tĩnh (trừ khi bạn sử dụng các con trỏ hàm)
  • Người viết trình biên dịch đã có nhiều thời gian để cải thiện mã tối ưu hóa. Ngoài ra, mọi người lập trình trong C với mục đích đạt được hiệu suất tốt nhất, do đó có áp lực để tối ưu hóa mã.
  • Các phần của đặc tả ngôn ngữ được xác định theo triển khai, vì vậy trình biên dịch có thể tự do thực hiện mọi thứ theo cách tối ưu nhất

Hầu hết các ngôn ngữ gõ tĩnh có thể được biên dịch nhanh hoặc nhanh hơn C, đặc biệt là nếu chúng có thể đưa ra các giả định mà C không thể vì bí danh con trỏ, v.v.


C cấp thấp? Tôi đoán bây giờ nó có nghĩa tương đối, so với Java có nhưng so với lắp ráp không. Bài đăng tốt, làm tôi suy nghĩ.
Đánh dấu

Bạn nói đúng, nó chắc chắn là tương đối. Ý tôi là nó "gần với máy" và không giúp bạn làm những việc như quản lý bộ nhớ hoặc theo dõi kích thước mảng.
Matthew Crumley

2
C là một ngôn ngữ cấp thấp. C luôn là một ngôn ngữ cấp thấp. Bạn dịch tay mã C vào trình biên dịch mà không gặp nhiều khó khăn.
Robert C. Barth

2
@Robert: C từng được coi là ngôn ngữ cấp cao vì so với lắp ráp (vốn rất phổ biến), nó đã được. Nó được coi là một ngôn ngữ cấp thấp so với phần lớn các ngôn ngữ được sử dụng ngày nay.
Robert Gamble

Thành thật mà nói, đây là một câu trả lời rất thiên vị. Chết tiệt gần tất cả các lập trình viên C kiểm tra giới hạn, v.v ... Tuy nhiên, C vẫn còn NHIỀU nhanh hơn C ++.
MarcusJ

8

Tôi đoán bạn đã quên rằng ngôn ngữ hội cũng là một ngôn ngữ :)

Nhưng nghiêm túc, các chương trình C chỉ nhanh hơn khi lập trình viên biết mình đang làm gì. Bạn có thể dễ dàng viết một chương trình C chạy chậm hơn các chương trình được viết bằng các ngôn ngữ khác làm cùng một công việc.

Lý do tại sao C nhanh hơn là vì nó được thiết kế theo cách này. Nó cho phép bạn thực hiện nhiều công cụ "cấp thấp hơn" giúp trình biên dịch tối ưu hóa mã. Hoặc, chúng tôi sẽ nói, bạn lập trình viên chịu trách nhiệm tối ưu hóa mã. Nhưng nó thường khá phức tạp và dễ bị lỗi.

Các ngôn ngữ khác, như những ngôn ngữ khác đã được đề cập, tập trung nhiều hơn vào năng suất của lập trình viên. Người ta thường tin rằng thời gian lập trình viên đắt hơn nhiều so với thời gian máy (ngay cả trong thời đại cũ). Vì vậy, sẽ rất có ý nghĩa để giảm thiểu thời gian lập trình viên dành cho việc viết và gỡ lỗi chương trình thay vì thời gian chạy chương trình. Để làm điều đó, bạn sẽ hy sinh một chút về những gì bạn có thể làm để làm cho chương trình nhanh hơn vì rất nhiều thứ được tự động hóa.


3
Mặc dù nếu bạn đã viết một chương trình một lần trong C và một lần nữa trong hội, phiên bản C có thể sẽ nhanh hơn vì trình biên dịch thông minh hơn bạn.
mk12

7

Đối với hầu hết các phần, mỗi lệnh C tương ứng với một vài lệnh biên dịch hợp ngữ. Về cơ bản, bạn đang viết mã máy cấp cao hơn, vì vậy bạn có quyền kiểm soát hầu hết mọi thứ mà bộ xử lý làm. Nhiều ngôn ngữ được biên dịch khác, chẳng hạn như C ++, có rất nhiều hướng dẫn tìm kiếm đơn giản có thể biến thành nhiều mã hơn bạn nghĩ (các hàm ảo, sao chép hàm tạo, v.v.) Và các ngôn ngữ được dịch như Java hoặc Ruby có một lớp khác hướng dẫn mà bạn không bao giờ thấy - Máy ảo hoặc Trình thông dịch.


Và một số ngôn ngữ cấp cao này tự hào rằng họ có thể loại bỏ hầu hết các hành trình mà họ đã thêm vào ngay từ đầu. Những thứ như sao chép, tối ưu hóa giá trị trả về, di chuyển xây dựng / chuyển nhượng, v.v. trong C ++.
cmaster - phục hồi monica

Vì vậy, tất cả đi vào số lượng hướng dẫn lắp ráp được tạo ra từ mã. Có nhiều hướng dẫn lắp ráp trên mỗi dòng mã cấp cao, hiệu năng càng bị ảnh hưởng?
ENDEESA

Đó có thể là một sự đơn giản hóa, nhưng có một mối quan hệ trực tiếp giữa số lượng hướng dẫn lắp ráp và tốc độ chương trình. Có một lượng thời gian tối thiểu để bộ xử lý thực hiện mỗi lệnh. IMHO, một ngôn ngữ cho phép bạn dễ dàng hiểu được bao nhiêu hướng dẫn bạn đang viết giúp bạn viết mã hiệu quả hơn. (Có các chi phí thời gian của bộ xử lý khác, như phân nhánh và bộ nhớ cache bị mất, nhưng ngay cả ở đó, việc trừu tượng hóa ít hơn cũng giúp làm rõ CPU đang làm gì).
HỎI

7

Tôi biết nhiều người đã nói điều đó một cách dài dòng, nhưng:

C nhanh hơn vì nó làm ít hơn (đối với bạn).


Điều này. Rất đúng với tinh thần của C.
cmaster - phục hồi monica

7

C ++ trung bình nhanh hơn (như ban đầu, phần lớn là siêu khối của C, mặc dù có một số khác biệt). Tuy nhiên, đối với các điểm chuẩn cụ thể, thường có một ngôn ngữ khác nhanh hơn.

https://benchmarkgame-team.pages.debian.net/benchmarkgame/

fannjuch-redux nhanh nhất ở Scala

n-bodyfastađã nhanh hơn trong Ada.

spectral-norm là nhanh nhất ở Fortran.

reverse-complement, mandelbrotpidigitslà nhanh nhất trong ATS.

regex-dna là nhanh nhất trong JavaScript.

chameneou-redux nhanh nhất là Java 7.

thread-ring là nhanh nhất trong Haskell.

Phần còn lại của điểm chuẩn là nhanh nhất trong C hoặc C ++.


"vì nó là một bộ siêu C" - Không, C ++ không phải là siêu bộ của C.
PP

1
extern "C"không có gì để làm với C ++ là một superset của C.
PP

2
Nó giống như nói system("bash script.sh");hoạt động cho bất kỳ tập lệnh bash nào, và do đó C là một siêu tập tin bash. extern "C"cung cấp liên kết C trong C ++ do xáo trộn tên. Trong khi đó, gọi X là superset của Y có nghĩa là bất cứ điều gì có thể được thực hiện trong Y cũng có thể được thực hiện trong X, điều này không đúng với C ++. Có khá nhiều cấu trúc ngôn ngữ hợp lệ trong C nhưng không có trong C ++.
PP

1
@PP Không có gì trong tiêu chuẩn C ++ bắt buộc đó bashlà chương trình dòng lệnh có sẵn. Nếu nó đã làm và bao gồm phiên bản / thông số kỹ thuật của bash cần được hỗ trợ, tôi sẽ xem xét nó là superset.
Peter Lawrey

1
nó trivially dễ dàng để viết mã C mà không phải là C ++, ví dụ:struct foo { int: this; }; typedef float foo;
Jasen

6

Nhiều câu trả lời trong số này đưa ra lý do hợp lệ cho lý do tại sao C là, hoặc không, nhanh hơn (nói chung hoặc trong các tình huống cụ thể). Không thể phủ nhận rằng:

  • Nhiều ngôn ngữ khác cung cấp các tính năng tự động mà chúng tôi được cấp. Ví dụ, kiểm tra giới hạn, kiểm tra loại thời gian chạy và quản lý bộ nhớ tự động, không đến miễn phí. Có ít nhất một số chi phí liên quan đến các tính năng này, điều mà chúng ta có thể không nghĩ về, hoặc thậm chí là nhận ra trong khi viết mã sử dụng các tính năng này.
  • Bước từ nguồn đến máy thường không trực tiếp bằng các ngôn ngữ khác như trong C.
  • OTOH, để nói rằng mã C được biên dịch thực thi nhanh hơn các mã khác được viết bằng các ngôn ngữ khác là một khái quát không phải lúc nào cũng đúng. Các ví dụ dễ tìm thấy (hoặc contrive).

Mặc dù vậy, có một điều khác tôi nhận thấy rằng, tôi nghĩ, ảnh hưởng đến hiệu suất so sánh của C so với nhiều ngôn ngữ khác nhiều hơn bất kỳ yếu tố nào khác. Để dí dỏm:

Các ngôn ngữ khác thường làm cho việc viết mã thực thi chậm hơn. Thông thường, nó thậm chí còn được khuyến khích bởi các triết lý thiết kế của ngôn ngữ. Hệ quả: một lập trình viên C có nhiều khả năng viết mã không thực hiện các hoạt động không cần thiết.

Ví dụ, hãy xem xét một chương trình Windows đơn giản trong đó một cửa sổ chính duy nhất được tạo. Phiên bản AC sẽ tạo ra một WNDCLASS[EX]cấu trúc sẽ được chuyển đến RegisterClass[Ex], sau đó gọi CreateWindow[Ex]và nhập một vòng lặp tin nhắn. Mã đơn giản và viết tắt cao như sau:

WNDCLASS wc;
MSG      msg;

wc.style         = 0;
wc.lpfnWndProc   = &WndProc;
wc.cbClsExtra    = 0;
wc.cbWndExtra    = 0;
wc.hInstance     = hInstance;
wc.hIcon         = NULL;
wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.lpszMenuName  = NULL;
wc.lpszClassName = "MainWndCls";

RegisterClass(&wc);

CreateWindow("MainWndCls", "", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
             CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

while(GetMessage(&msg, NULL, 0, 0)){
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

Một chương trình tương đương trong C # có thể chỉ là một dòng mã:

Application.Run(new Form());

Một dòng mã này cung cấp tất cả các chức năng mà gần 20 dòng mã C đã làm và thêm một số thứ chúng tôi bỏ qua, chẳng hạn như kiểm tra lỗi. Thư viện phong phú hơn, đầy đủ hơn (so với những thư viện được sử dụng trong một dự án C điển hình) đã làm rất nhiều việc cho chúng tôi, giải phóng thời gian của chúng tôi để viết nhiều đoạn mã ngắn hơn cho chúng tôi nhưng liên quan đến nhiều bước phía sau hậu trường.

Nhưng một thư viện phong phú cho phép phình mã dễ dàng và nhanh chóng không thực sự là quan điểm của tôi. Quan điểm của tôi rõ ràng hơn khi bạn bắt đầu kiểm tra những gì thực sự xảy ra khi một lớp lót nhỏ của chúng tôi thực sự thực thi. Để giải trí, đôi khi, cho phép truy cập nguồn .NET trong Visual Studio 2008 trở lên và bước vào một dòng đơn giản ở trên. Một trong những viên ngọc nhỏ thú vị mà bạn sẽ bắt gặp là nhận xét này trong getter cho Control.CreateParams:

// In a typical control this is accessed ten times to create and show a control.
// It is a net memory savings, then, to maintain a copy on control.
// 
if (createParams == null) {
    createParams = new CreateParams(); 
} 

Mười lần . Thông tin gần tương đương với tổng của những gì được lưu trữ trong một WNDCLASSEXcấu trúc và những gì được truyền đến CreateWindowExđược lấy từ Controllớp mười lần trước khi nó được lưu trữ trong một WNDCLASSEXcấu trúc và được truyền cho RegisterClassExCreateWindowEx .

Nói chung, số lượng lệnh được thực thi để thực hiện nhiệm vụ rất cơ bản này là 2 lệnh3 độ lớn hơn trong C # so với C. Một phần của điều này là do việc sử dụng thư viện giàu tính năng, nhất thiết phải được khái quát hóa, so với mã C đơn giản của chúng tôi thực hiện chính xác những gì chúng tôi cần và không có gì hơn. Nhưng một phần của nó là do bản chất được mô đun hóa, hướng đối tượng của .NET framework, cho vay rất nhiều sự lặp lại của việc thực thi thường bị tránh bởi một cách tiếp cận theo thủ tục.

Tôi không cố gắng chọn C # hoặc .NET framework. Tôi cũng không nói rằng mô đun hóa, khái quát hóa, các tính năng thư viện / ngôn ngữ, OOP, vv là những điều xấu . Tôi đã từng thực hiện hầu hết sự phát triển của mình trong C, sau đó là C ++ và gần đây nhất là C #. Tương tự, trước C, tôi đã sử dụng phần lớn là lắp ráp. Và với mỗi bước "cao hơn" ngôn ngữ của tôi đi, tôi viết các chương trình tốt hơn, dễ bảo trì hơn, mạnh mẽ hơn trong thời gian ngắn hơn. Họ làm, tuy nhiên, có xu hướng thực hiện chậm hơn một chút.


2
Đó là vấn đề API, không phải vấn đề ngôn ngữ.
Arafangion

1
@Arafangion: Tôi hiểu những gì bạn đang nói, nhưng nó không đúng. Thư viện giàu tính năng được kích hoạt (và, theo một cách nào đó, được yêu cầu) bởi ngôn ngữ giàu tính năng. Và đó không chỉ là thư viện. Thư viện chỉ là một ví dụ về việc sử dụng phổ biến ngôn ngữ. Mã ứng dụng điển hình trong bất kỳ ngôn ngữ nào thường có sự tương đồng với các thư viện thường được sử dụng trong ngôn ngữ đó. Đó thực sự là một suy nghĩ được thúc đẩy bởi ngôn ngữ. Ví dụ, các ngôn ngữ OO thường dành nhiều thời gian hơn để phân bổ, xây dựng, phá hủy và phân bổ các đối tượng so với các ngôn ngữ có ít hỗ trợ OOP hơn.
P Daddy

Tôi sẽ thừa nhận rằng một lựa chọn ngôn ngữ nhất định thường ngụ ý một nền tảng và thư viện cụ thể, đó là lý do tại sao tôi đưa ra nhận xét đó (để người đọc nhận thức rõ hơn), nhưng nói rằng, sử dụng (ví dụ) C ++ trên windows là một Con thú rất khác với C ++ trên linux và khác với C ++ trên Android. Một ví dụ khác là Python - chúng tôi có CPython, Jython, PyPy và IronPython - tất cả đều sử dụng các thư viện rất khác nhau.
Arafangion

Nhưng sử dụng bất kỳ Pythons nào, các nhà phát triển sẽ có xu hướng viết các ứng dụng theo một cách nhất định. Ví dụ, họ có thể đọc và ghi từ tệp văn bản, tạo các đối tượng mới với dữ liệu họ đọc. Mặt khác, trong C, một nhà phát triển nhiều khả năng sẽ thực hiện phân bổ một lần cho một mảng các cấu trúc, và đọc và viết các cấu trúc đó từ một tệp nhị phân. Tất nhiên, đây chỉ đơn giản là một ví dụ giả định cố gắng minh họa điểm mà tôi đang cố gắng đưa ra về tư duy .
P Daddy

6

Tôi không nghĩ có ai đã đề cập đến thực tế rằng nhiều nỗ lực đã được đưa vào trình biên dịch C hơn bất kỳ trình biên dịch nào khác, có lẽ ngoại trừ Java.

C cực kỳ tối ưu hóa có thể vì nhiều lý do đã được nêu - nhiều hơn hầu hết các ngôn ngữ khác. Vì vậy, nếu cùng một lượng nỗ lực được đưa vào các trình biên dịch ngôn ngữ khác, C có thể vẫn sẽ đứng đầu.

Tôi nghĩ rằng có ít nhất một ngôn ngữ ứng cử viên với nỗ lực có thể được tối ưu hóa tốt hơn C và do đó chúng ta có thể thấy các triển khai tạo ra các nhị phân nhanh hơn. Tôi đang nghĩ về sao hỏa kỹ thuật số D vì người sáng tạo đã quan tâm xây dựng một ngôn ngữ có khả năng tối ưu hóa tốt hơn C. Có thể có các ngôn ngữ khác có khả năng này. Tuy nhiên tôi không thể tưởng tượng rằng bất kỳ ngôn ngữ nào cũng sẽ có trình biên dịch nhanh hơn chỉ vài phần trăm so với trình biên dịch C tốt nhất. Tôi rất thích được sai.

Tôi nghĩ rằng "trái cây treo thấp" thực sự sẽ có trong các ngôn ngữ được thiết kế để DỄ DÀNG để con người tối ưu hóa. Một lập trình viên lành nghề có thể làm cho bất kỳ ngôn ngữ nào đi nhanh hơn - nhưng đôi khi bạn phải làm những điều lố bịch hoặc sử dụng các cấu trúc không tự nhiên để thực hiện điều này. Mặc dù sẽ luôn nỗ lực, một ngôn ngữ tốt sẽ tạo ra mã tương đối nhanh mà không phải ám ảnh chính xác cách chương trình được viết.

Điều quan trọng nữa (ít nhất là với tôi) là mã trường hợp xấu nhất có xu hướng nhanh. Có rất nhiều "bằng chứng" trên web rằng Java nhanh hoặc nhanh hơn C, nhưng điều đó dựa trên các ví dụ chọn anh đào. Tôi không phải là fan hâm mộ lớn của C, nhưng tôi biết rằng BẤT CỨ điều gì tôi viết bằng C sẽ chạy tốt. Với Java, "có thể" sẽ chạy trong vòng 15% tốc độ, thường là trong vòng 25% nhưng trong một số trường hợp, nó có thể tồi tệ hơn nhiều. Bất kỳ trường hợp nào chỉ nhanh hoặc trong một vài phần trăm thường là do phần lớn thời gian được sử dụng trong mã thư viện được tối ưu hóa C rất nhiều.


5

Đây thực sự là một chút sai lầm vĩnh viễn. Mặc dù sự thật là các chương trình C thường nhanh hơn, nhưng điều này không phải lúc nào cũng đúng, đặc biệt là nếu lập trình viên C không giỏi về nó.

Một lỗ hổng lớn mà mọi người có xu hướng quên là khi chương trình phải chặn một số loại IO, chẳng hạn như đầu vào của người dùng trong bất kỳ chương trình GUI nào. Trong những trường hợp này, việc bạn sử dụng ngôn ngữ nào thực sự không quan trọng vì bạn bị giới hạn bởi tốc độ dữ liệu có thể đến thay vì tốc độ bạn có thể xử lý ngôn ngữ đó. Trong trường hợp này, sẽ không có vấn đề gì nhiều nếu bạn đang sử dụng C, Java, C # hoặc thậm chí Perl; bạn không thể đi nhanh hơn dữ liệu có thể đi vào.

Một điều quan trọng khác là việc sử dụng bộ sưu tập rác và không sử dụng các con trỏ thích hợp cho phép máy ảo thực hiện một số tối ưu hóa không khả dụng trong các ngôn ngữ khác. Ví dụ, JVM có khả năng di chuyển các đối tượng xung quanh trên heap để chống phân mảnh nó. Điều này làm cho phân bổ trong tương lai nhanh hơn nhiều vì chỉ mục tiếp theo có thể được sử dụng đơn giản hơn là tìm kiếm trong bảng. Các JVM hiện đại cũng không phải thực sự giải phóng bộ nhớ; thay vào đó, họ chỉ di chuyển các đối tượng sống xung quanh khi họ GC và bộ nhớ đã sử dụng từ các đối tượng chết về cơ bản được phục hồi miễn phí.

Điều này cũng mang đến một điểm thú vị về C và thậm chí còn hơn thế trong C ++. Có một cái gì đó của triết lý thiết kế "Nếu bạn không cần nó, bạn không phải trả tiền cho nó." Vấn đề là nếu bạn muốn nó, cuối cùng bạn sẽ trả tiền qua mũi cho nó. Chẳng hạn, việc triển khai vtable trong Java có xu hướng tốt hơn rất nhiều so với triển khai C ++, vì vậy các cuộc gọi hàm ảo nhanh hơn rất nhiều. Mặt khác, bạn không có lựa chọn nào khác ngoài việc sử dụng các hàm ảo trong Java và chúng vẫn có chi phí gì đó, nhưng trong các chương trình sử dụng nhiều hàm ảo, chi phí giảm sẽ tăng thêm.


1
"Việc triển khai vtable trong Java có xu hướng tốt hơn rất nhiều so với triển khai C ++, vì vậy các cuộc gọi hàm ảo nhanh hơn rất nhiều." Làm thế nào trên trái đất bạn có thể đi nhanh hơn MOV EAX, [ECX]; GỌI [EAX + someindex]; ? Trừ khi bạn có thể gọi một chức năng mà không cần tìm kiếm, điều này có vẻ khá tối ưu.
Frans-Willem

@Frans - trình biên dịch JIT (như Java HotSpot) có thể nội tuyến tra cứu vtable nếu nó xác định một đối tượng đã cho luôn luôn là một kiểu nhất định. C ++ cũng sẽ làm điều này nếu nó biết thông tin tương tự tại thời gian biên dịch, nhưng việc thực hiện tối ưu hóa này bằng mã byte Java sẽ dễ dàng hơn so với hướng dẫn máy x86.
Tom

6
@James - Lập luận "I / O làm cho vấn đề hiệu suất ít hơn" không làm mất hiệu lực câu lệnh "C nhanh hơn các ngôn ngữ khác". Đó không phải là một lỗ hổng rõ ràng, đó là một cuộc tranh cãi rơm.
Tom

Sẽ tốt hơn nếu sử dụng xử lý chuỗi của C (và cả thư viện C tiêu chuẩn) làm ví dụ, vì đó là khu vực mà C kém. Hầu hết các ngôn ngữ khác làm tốt hơn, ngay cả với mã bắt đầu đơn giản.
Donal Fellows

@DonalFellows các hàm mem * có thể nhanh hơn các hàm str * trên một số tác vụ, nhưng xử lý chuỗi là hiệu quả nếu được thực hiện cẩn thận. bạn đã có một điểm chuẩn cụ thể trong tâm trí?
Jasen

4

Đó không phải là quá nhiều về ngôn ngữ như các công cụ và thư viện. Các thư viện và trình biên dịch có sẵn cho C cũ hơn nhiều so với các ngôn ngữ mới hơn. Bạn có thể nghĩ rằng điều này sẽ làm cho chúng chậm hơn, nhưng au contraire.

Các thư viện này được viết vào thời điểm sức mạnh xử lý và bộ nhớ ở mức cao. Chúng phải được viết rất hiệu quả để làm việc. Các nhà phát triển trình biên dịch C cũng đã có một thời gian dài để làm việc trong tất cả các loại tối ưu hóa thông minh cho các bộ xử lý khác nhau. Sự trưởng thành và áp dụng rộng rãi của C tạo nên lợi thế đáng kể so với các ngôn ngữ khác cùng tuổi. Nó cũng mang lại cho C lợi thế về tốc độ so với các công cụ mới hơn, không nhấn mạnh hiệu năng thô nhiều như C đã có.


4

Sự thiếu trừu tượng là điều làm cho C nhanh hơn. Nếu bạn viết một tuyên bố đầu ra, bạn biết chính xác những gì đang xảy ra. Nếu bạn viết một câu lệnh đầu ra trong java, nó sẽ được biên dịch thành một tệp lớp và sau đó được chạy trên một máy ảo giới thiệu một lớp trừu tượng. Việc thiếu các tính năng hướng đối tượng là một phần của ngôn ngữ cũng làm tăng tốc độ của nó đối với việc tạo ra ít mã hơn. Nếu bạn sử dụng C làm ngôn ngữ hướng đối tượng thì bạn đang thực hiện tất cả mã hóa cho những thứ như lớp học, tính không đúng, v.v. Điều này có nghĩa là sau đó tạo ra một cái gì đó đủ khái quát cho mọi người với số lượng mã và bút hiệu suất yêu cầu bạn chỉ viết những gì bạn cần để hoàn thành công việc


4

Thật ngạc nhiên khi thấy "C / C ++ cũ phải nhanh hơn Java vì Java được hiểu" huyền thoại vẫn còn sống và đang phát triển. Có những bài báo trở lại một vài năm , cũng như những bài gần đây , giải thích với các khái niệm hoặc phép đo tại sao điều này đơn giản không phải luôn luôn như vậy .

Việc triển khai máy ảo hiện tại (và không chỉ là JVM) có thể tận dụng thông tin được thu thập trong quá trình thực thi chương trình để tự động điều chỉnh mã khi chạy, sử dụng nhiều kỹ thuật:

  • kết xuất các phương thức thường xuyên với mã máy
  • nội tuyến phương pháp nhỏ,
  • điều chỉnh khóa

một loạt các điều chỉnh khác dựa trên việc biết mã thực sự đang làm gì và dựa trên các đặc điểm thực tế của môi trường mà nó đang chạy.


Tôi đồng ý rằng Java đã thực hiện cải tiến hiệu suất đáng kể trong vài năm trở lại đây mà mang nó gần gũi hơn với C về hiệu suất thô nhưng nó sẽ mất một thời gian để sống xuống thực tế là nó đã quá chậm cho nên dài. Nhưng ai đã nói về Java?
Robert Gamble

Java là một "ngôn ngữ khác" được tham chiếu bởi OP, phải không?
Robert C. Barth

@Robert: "các ngôn ngữ khác", số nhiều, không đề cập đến bất kỳ ngôn ngữ cụ thể nào ngoài C. Làm thế nào bạn có thể đọc "Java" từ đó?
Robert Gamble

@Roberd: Một số câu trả lời đã được đăng trước khi tôi gặp câu hỏi là nói về Java (hoặc các ngôn ngữ khác có triển khai thường thông qua trình thông dịch hoặc VM).
joel.neely

3
@Joel - Nếu bạn biết phần cứng mục tiêu của mình, hầu hết các tối ưu hóa JVM có thể thực hiện trong thời gian chạy cũng có thể được thực hiện bằng cách sử dụng tối ưu hóa theo hướng dẫn hồ sơ với C hoặc C ++. Điều đó tạo ra một sự khác biệt lớn và nói chung đẩy C và C ++ trở lại vị trí dẫn đầu, vì họ không phải "học" trong khi thực hiện.
Tom

4

Mã chạy nhanh nhất sẽ được mã thủ công cẩn thận. Trình biên dịch sẽ gần như tốt. Cả hai đều ở mức rất thấp và phải mất rất nhiều mã viết để làm việc. C là một chút trên lắp ráp. Bạn vẫn có khả năng kiểm soát mọi thứ ở mức rất thấp trong máy thực tế, nhưng có đủ sự trừu tượng hóa để viết nó nhanh hơn và dễ dàng hơn sau đó là trình biên dịch. Các ngôn ngữ khác như C # và JAVA thậm chí còn trừu tượng hơn. Trong khi Trình biên dịch và mã máy được gọi là ngôn ngữ cấp thấp, C # và JAVA (và nhiều ngôn ngữ khác) được gọi là ngôn ngữ cấp cao. C đôi khi được gọi là ngôn ngữ trung cấp.


Trong khi đọc câu trả lời của bạn, chỉ hai từ trong toàn bộ đoạn văn đang kéo mắt tôi về phía họ, giống như một nam châm kéo kim loại. Từ này là JAVA, hai lần trong đoạn văn. Chưa bao giờ nhìn thấy nó trước khi được viết trong tất cả các mũ, và nó trông thật tuyệt :-)
Sнаđошƒаӽ 2/12/2016

3

Đừng lấy từ của ai đó cho nó, hãy xem phần phân tách cho cả C và ngôn ngữ bạn chọn trong bất kỳ phần quan trọng nào về hiệu suất của mã. Tôi nghĩ bạn chỉ cần nhìn vào cửa sổ tháo gỡ trong thời gian chạy trong Visual Studio để thấy .Net đã được tháo rời. Nên có thể nếu Java khó sử dụng Windbg, mặc dù nếu bạn làm điều đó với .Net thì nhiều vấn đề sẽ giống nhau.

Tôi không muốn viết bằng C nếu tôi không cần, nhưng tôi nghĩ rằng nhiều tuyên bố được đưa ra trong các câu trả lời này cho thấy tốc độ của các ngôn ngữ khác ngoài C có thể được đặt sang một bên bằng cách đơn giản tách rời cùng một thói quen trong C và trong ngôn ngữ lựa chọn cấp cao hơn của bạn, đặc biệt nếu có nhiều dữ liệu liên quan như thường thấy trong các ứng dụng quan trọng về hiệu năng. Fortran có thể là một ngoại lệ trong lĩnh vực chuyên môn của nó, không biết. Có phải cấp độ cao hơn C?

Lần đầu tiên tôi đã so sánh mã JITed với mã gốc đã giải quyết bất kỳ và tất cả các câu hỏi liệu mã .Net có thể chạy tương đương với mã C hay không. Mức độ trừu tượng thêm và tất cả các kiểm tra an toàn đi kèm với một chi phí đáng kể. Các chi phí tương tự có thể sẽ áp dụng cho Java, nhưng đừng hiểu ý tôi, hãy thử nó trên một cái gì đó mà hiệu suất là rất quan trọng. (Bất cứ ai cũng biết đủ về Java JITed để tìm một thủ tục được biên dịch trong bộ nhớ? Điều đó chắc chắn là có thể)


2

1) Như những người khác đã nói, C làm ít hơn cho bạn. Không khởi tạo biến, không kiểm tra giới hạn mảng, không quản lý bộ nhớ, v.v. Những tính năng trong các ngôn ngữ khác có chi phí bộ nhớ và chu kỳ CPU mà C không chi tiêu.

2) Câu trả lời nói rằng C ít trừu tượng hơn và do đó nhanh hơn chỉ đúng một nửa tôi nghĩ. Về mặt kỹ thuật, nếu bạn có "trình biên dịch đủ nâng cao" cho ngôn ngữ X, thì ngôn ngữ X có thể tiếp cận hoặc bằng tốc độ của C. Sự khác biệt với C là vì nó ánh xạ rất rõ ràng (nếu bạn đã tham gia khóa học kiến ​​trúc) và trực tiếp đến ngôn ngữ lắp ráp mà ngay cả một trình biên dịch ngây thơ cũng có thể làm một công việc tốt. Đối với một cái gì đó như Python, bạn cần một trình biên dịch rất tiên tiến để dự đoán các loại đối tượng có thể xảy ra và tạo mã máy khi đang di chuyển - ngữ nghĩa của C đủ đơn giản để trình biên dịch đơn giản có thể làm tốt.


2

Quay trở lại những ngày tốt lành, chỉ có hai loại ngôn ngữ: được biên dịch và giải thích.

Các ngôn ngữ được biên dịch sử dụng một "trình biên dịch" để đọc cú pháp ngôn ngữ và chuyển đổi nó thành mã ngôn ngữ lắp ráp giống hệt nhau, có thể chỉ trực tiếp trên CPU. Các ngôn ngữ được giải thích đã sử dụng một vài lược đồ khác nhau, nhưng về cơ bản, cú pháp ngôn ngữ đã được chuyển đổi thành dạng trung gian và sau đó chạy trong "trình thông dịch", một môi trường để thực thi mã.

Do đó, theo một nghĩa nào đó, có một "lớp" khác - trình thông dịch - giữa mã và máy. Và, như mọi khi trong máy tính, nhiều tài nguyên hơn có nghĩa là được sử dụng nhiều hơn. Thông dịch viên chậm hơn, vì họ phải thực hiện nhiều thao tác hơn.

Gần đây, chúng tôi đã thấy nhiều ngôn ngữ lai như Java, sử dụng cả trình biên dịch và trình thông dịch để làm cho chúng hoạt động. Nó phức tạp, nhưng một JVM nhanh hơn, tinh vi hơn và được tối ưu hóa hơn so với các trình thông dịch cũ, do đó, nó thay đổi hiệu suất tốt hơn nhiều (theo thời gian) gần hơn với mã được biên dịch thẳng. Tất nhiên, các trình biên dịch mới hơn cũng có các thủ thuật tối ưu hóa lạ mắt hơn để chúng có xu hướng tạo ra mã tốt hơn so với trước đây. Nhưng hầu hết các tối ưu hóa, thường xuyên nhất (mặc dù không phải lúc nào cũng) tạo ra một số loại đánh đổi sao cho chúng không phải lúc nào cũng nhanh hơn trong mọi hoàn cảnh. Giống như mọi thứ khác, không có gì miễn phí, vì vậy các trình tối ưu hóa phải tự hào từ đâu đó (mặc dù thường sử dụng CPU thời gian biên dịch để tiết kiệm CPU thời gian chạy).

Quay trở lại C, đó là một ngôn ngữ đơn giản, có thể được biên dịch thành tập hợp khá tối ưu hóa và sau đó chạy trực tiếp trên máy đích. Trong C, nếu bạn tăng một số nguyên, nhiều khả năng đó chỉ là một bước biên dịch trong CPU, tuy nhiên, trong Java, nó có thể sẽ còn nhiều hơn thế (và cũng có thể bao gồm một chút bộ sưu tập rác: -) C cung cấp cho bạn một bản tóm tắt gần với máy hơn (trình biên dịch là gần nhất), nhưng cuối cùng bạn phải thực hiện nhiều công việc hơn để làm cho nó hoạt động và nó không được bảo vệ, dễ sử dụng hoặc thân thiện với lỗi. Hầu hết các ngôn ngữ khác cung cấp cho bạn mức độ trừu tượng cao hơn và quan tâm nhiều hơn đến các chi tiết cơ bản cho bạn, nhưng để đổi lấy chức năng nâng cao của chúng, chúng đòi hỏi nhiều tài nguyên hơn để chạy. Khi bạn khái quát một số giải pháp, bạn phải xử lý một phạm vi rộng hơn của máy tính,

Paul.


"Trong C, nếu bạn tăng một số nguyên, nhiều khả năng đó chỉ là một bước biên dịch trong CPU" Không hoàn toàn chính xác. Nếu số nguyên này không có trong thanh ghi CPU, thì bạn cần phải có mã máy để lấy nó từ bộ nhớ, tăng nó, ghi lại vào bộ nhớ. Về cùng một điều sẽ xảy ra khi chạy mã Java. Và tôi không hiểu tại sao "++ i" lại tự kích hoạt chu trình GC.
quant_dev

@quant_dev: "bạn .. có ... để lấy nó từ bộ nhớ, tăng nó lên, viết lại ...". Co le không. Ví dụ, x86 có các hướng dẫn hoạt động trên dữ liệu trong bộ nhớ. ++icó thể biên dịch thành "thêm [ebp - 8], 1". Không nói rằng việc tìm nạp, gia tăng, lưu trữ vẫn không xảy ra, nhưng điều này được CPU quan tâm và chỉ là một hướng dẫn, như Paul nói.
P Daddy

... vẫn không liên quan đến POV về hiệu năng, bởi vì nó có thể chỉ là một hướng dẫn, nhưng vẫn liên quan đến việc chờ dữ liệu đến CPU. Cache nhớ và tất cả những thứ đó.
quant_dev

Không, tôi sẽ không nói nó không liên quan. Một lệnh CPU thường chiếm ít byte mã hơn so với nhiều lệnh CPU, mang lại hiệu năng bộ đệm tốt hơn trên đoạn mã. Một lệnh CPU cũng chiếm ít chỗ hơn trên đường ống của CPU và có thể xử lý nhiều bước (tìm nạp, tăng, lưu trữ) trong các giai đoạn đường ống riêng biệt. Trên thực tế, một số phần của một hoạt động thậm chí có thể bị bỏ qua nếu chúng có thể được kết hợp với các hoạt động khác trên đường ống. Chẳng hạn, việc lưu trữ một giá trị có thể được kết hợp với lần tải tiếp theo của cùng một giá trị.
P Daddy

2

Đặt các kỹ thuật tối ưu hóa tiên tiến như tối ưu hóa điểm nóng , thuật toán meta được biên dịch sẵn và các dạng song song khác nhau , tốc độ cơ bản của ngôn ngữ tương quan mạnh mẽ với độ phức tạp phía sau hậu trường cần thiết để hỗ trợ các hoạt động thường gặp được chỉ định trong các vòng bên trong .

Có lẽ rõ ràng nhất là kiểm tra tính hợp lệ trên các tham chiếu bộ nhớ gián tiếp - chẳng hạn như kiểm tra các con trỏ nullvà kiểm tra các chỉ mục theo các ranh giới mảng. Hầu hết các ngôn ngữ cấp cao đều thực hiện các kiểm tra này một cách ngầm định, nhưng C thì không. Tuy nhiên, đây không nhất thiết là giới hạn cơ bản của các ngôn ngữ khác - một trình biên dịch đủ thông minh có thể có khả năng loại bỏ các kiểm tra này khỏi các vòng lặp bên trong của thuật toán thông qua một số dạng chuyển động mã bất biến vòng lặp .

Ưu điểm cơ bản hơn của C (và ở một mức độ tương tự, C ++ có liên quan chặt chẽ) là sự phụ thuộc nặng nề vào phân bổ bộ nhớ dựa trên ngăn xếp , vốn đã nhanh chóng để phân bổ, phân bổ và truy cập. Trong C (và C ++), ngăn xếp cuộc gọi chính có thể được sử dụng để phân bổ các nguyên hàm, mảng và tổng hợp ( struct/ class).

Mặc dù C cung cấp khả năng phân bổ động bộ nhớ có kích thước và tuổi thọ tùy ý (sử dụng cái gọi là 'heap'), nhưng làm như vậy được tránh theo mặc định (thay vào đó ngăn xếp được sử dụng).

Tantalizingly, đôi khi có thể sao chép chiến lược cấp phát bộ nhớ C trong môi trường thời gian chạy của các ngôn ngữ lập trình khác. Điều này đã được chứng minh bởi asm.js , cho phép mã được viết bằng C hoặc C ++ được dịch sang một tập hợp con của JavaScript và chạy an toàn trong môi trường trình duyệt web - với tốc độ gần như nguyên gốc.


Như một phần của một bên, một lĩnh vực khác mà C và C ++ vượt trội hơn hầu hết các ngôn ngữ khác về tốc độ là khả năng tích hợp liền mạch với các bộ hướng dẫn máy gốc. Một ví dụ đáng chú ý ở đây là tính khả dụng (phụ thuộc vào trình biên dịch và nền tảng) của nội tại SIMD hỗ trợ xây dựng các thuật toán tùy chỉnh tận dụng phần cứng xử lý song song gần như phổ biến hiện nay - trong khi vẫn sử dụng các tóm tắt phân bổ dữ liệu do ngôn ngữ cung cấp (thấp hơn phân bổ đăng ký -level được quản lý bởi trình biên dịch).


1
Một số lợi thế phân bổ bộ nhớ này của C có thể cũng có thể được nhân rộng trong các ngôn ngữ khác bằng các trình biên dịch thông minh (xem tại đây ). Mặc dù vậy, tôi có ấn tượng rằng điều này bằng cách nào đó có cấu trúc rất khó thực hiện - đặc biệt là đối với các kiểu dữ liệu không nguyên thủy. Bài viết này đề cập đến ý tưởng về một đối tượng không thoát có thể được phân bổ ngăn xếp như là một tối ưu hóa trong Java.
tộc

2

Tôi đã tìm thấy Câu trả lời trên liên kết về lý do tại sao một số ngôn ngữ nhanh hơn và một số ngôn ngữ chậm hơn, tôi hy vọng điều này sẽ làm rõ hơn lý do tại sao C hoặc C ++ nhanh hơn các ngôn ngữ khác, Có một số ngôn ngữ khác cũng nhanh hơn C, nhưng chúng tôi không thể sử dụng tất cả chúng Một số giải thích -

Một trong những lý do lớn mà Fortran vẫn quan trọng là vì nó nhanh: các thói quen giòn số được viết bằng Fortran có xu hướng nhanh hơn các thói quen tương đương được viết bằng hầu hết các ngôn ngữ khác. Các ngôn ngữ đang cạnh tranh với Fortran trong không gian này C và C ++ - được sử dụng vì chúng cạnh tranh với hiệu suất này.

Điều này đặt ra câu hỏi: tại sao? Điều gì về C ++ và Fortran giúp chúng phát triển nhanh và tại sao chúng lại vượt trội hơn các ngôn ngữ phổ biến khác, như Java hay Python?

Phiên dịch so với biên dịch Có nhiều cách để phân loại và xác định ngôn ngữ lập trình, theo phong cách lập trình mà họ khuyến khích và các tính năng họ cung cấp. Khi nhìn vào hiệu suất, sự khác biệt lớn nhất là giữa các ngôn ngữ được dịch và các ngôn ngữ được biên dịch.

Sự phân chia không khó; đúng hơn là có một quang phổ. Cuối cùng, chúng tôi có các ngôn ngữ được biên dịch truyền thống, một nhóm bao gồm Fortran, C và C ++. Trong các ngôn ngữ này, có một giai đoạn biên dịch rời rạc để dịch mã nguồn của chương trình thành một dạng thực thi mà bộ xử lý có thể sử dụng.

Quá trình biên dịch này có một số bước. Mã nguồn được phân tích và phân tích cú pháp. Các lỗi mã hóa cơ bản như lỗi chính tả và lỗi chính tả có thể được phát hiện tại thời điểm này. Mã được phân tích cú pháp được sử dụng để tạo ra một biểu diễn trong bộ nhớ, cũng có thể được sử dụng để phát hiện lỗi lỗi Lần này, các lỗi ngữ nghĩa, chẳng hạn như các hàm gọi không tồn tại hoặc cố gắng thực hiện các phép toán số học trên chuỗi văn bản.

Đại diện trong bộ nhớ này sau đó được sử dụng để điều khiển một trình tạo mã, phần tạo ra mã thực thi. Tối ưu hóa mã, để cải thiện hiệu suất của mã được tạo, được thực hiện tại nhiều thời điểm trong quy trình này: tối ưu hóa mức cao có thể được thực hiện trên biểu diễn mã và tối ưu hóa cấp thấp hơn được sử dụng trên đầu ra của trình tạo mã.

Trên thực tế việc thực thi mã xảy ra sau đó. Toàn bộ quá trình biên dịch được sử dụng đơn giản để tạo ra một cái gì đó có thể được thực thi.

Ở phía đối diện, chúng tôi có phiên dịch viên. Các trình thông dịch sẽ bao gồm một giai đoạn phân tích cú pháp tương tự như trình biên dịch, nhưng điều này sau đó được sử dụng để thúc đẩy thực thi trực tiếp, với chương trình được chạy ngay lập tức.

Trình thông dịch đơn giản nhất có mã thực thi tương ứng với các tính năng khác nhau mà ngôn ngữ hỗ trợ, vì vậy nó sẽ có các chức năng để thêm số, nối chuỗi, bất cứ ngôn ngữ nào khác có. Khi nó phân tích mã, nó sẽ tra cứu hàm tương ứng và thực thi nó. Các biến được tạo trong chương trình sẽ được lưu trong một loại bảng tra cứu ánh xạ tên của chúng vào dữ liệu của chúng.

Ví dụ cực đoan nhất của kiểu trình thông dịch là một cái gì đó giống như một tệp bó hoặc tập lệnh shell. Trong các ngôn ngữ này, mã thực thi thường không được tích hợp vào chính trình thông dịch, mà là các chương trình độc lập, riêng biệt.

Vậy tại sao điều này tạo ra sự khác biệt cho hiệu suất? Nói chung, mỗi lớp của indirection làm giảm hiệu suất. Ví dụ, cách nhanh nhất để thêm hai số là có cả hai số đó trong các thanh ghi trong bộ xử lý và sử dụng lệnh thêm của bộ xử lý. Đó là những gì chương trình biên dịch có thể làm; họ có thể đặt các biến vào các thanh ghi và tận dụng các hướng dẫn của bộ xử lý. Nhưng trong các chương trình được giải thích, cùng một phép cộng có thể yêu cầu hai lần tra cứu trong một bảng các biến để tìm nạp các giá trị để thêm, sau đó gọi một hàm để thực hiện phép cộng. Hàm đó rất có thể sử dụng cùng một lệnh xử lý như chương trình đã biên dịch sử dụng để thực hiện bổ sung thực tế, nhưng tất cả các công việc bổ sung trước khi lệnh thực sự có thể được sử dụng làm cho mọi thứ chậm hơn.

Nếu bạn muốn biết thêm xin vui lòng kiểm tra Nguồn


1

Một số thuật toán C ++ nhanh hơn C và một số triển khai thuật toán hoặc mẫu thiết kế trong các ngôn ngữ khác có thể nhanh hơn C.

Khi mọi người nói rằng C nhanh, và sau đó chuyển sang nói về một số ngôn ngữ khác, họ thường sử dụng hiệu suất của C làm điểm chuẩn.


2
"Một số thuật toán C ++ nhanh hơn C" không có nghĩa. Bất kỳ "thuật toán C ++" nào cũng có thể được viết bằng C và ngược lại. Thuật toán là bất khả tri ngôn ngữ. C ++ về cơ bản bổ sung các tính năng cho C - và không có tính năng mới nào trong số này dẫn đến các thuật toán nhanh hơn (mặc dù chúng có thể dễ viết hơn).
Joseph Garvin

1
Rebuke cổ điển là thuật toán std :: sort .. std :: sort nhanh hơn bất kỳ thuật toán sắp xếp nào trong C - cách duy nhất để có hiệu suất tương tự trong C là mã hóa nó ở mọi nơi bạn muốn hoặc sử dụng macro - và thậm chí sau đó trình biên dịch có ít thông tin để tối ưu hóa.
Arafangion

1

Với các trình biên dịch tối ưu hóa hiện đại, rất khó có khả năng một chương trình C thuần túy sẽ nhanh hơn nhiều so với mã .net được biên dịch, nếu có. Với việc tăng cường năng suất mà các khuôn khổ như .net cung cấp các nhà phát triển, bạn có thể làm mọi thứ trong một ngày được sử dụng để mất vài tuần hoặc vài tháng trong C. thường xuyên Cùng với chi phí rẻ của phần cứng so với mức lương của một nhà phát triển, nó chỉ là CÁCH rẻ hơn để ghi các công cụ trong một ngôn ngữ cấp cao và ném phần cứng ở bất kỳ sự chậm chạp.

Lý do Jeff và Joel nói về C là ngôn ngữ "lập trình viên thực sự" là vì không có người nắm tay trong C. Bạn phải phân bổ bộ nhớ của riêng mình, phân bổ bộ nhớ đó, kiểm tra giới hạn của chính bạn, v.v. như đối tượng mới (); Không có bộ sưu tập rác, các lớp, OOP, khung thực thể, LINQ, thuộc tính, thuộc tính, trường hoặc bất cứ thứ gì tương tự. Bạn phải biết những thứ như số học con trỏ và làm thế nào để hủy bỏ con trỏ. Và, đối với vấn đề đó, biết và hiểu con trỏ là gì. Bạn phải biết khung stack là gì và con trỏ lệnh là gì. Bạn phải biết mô hình bộ nhớ của kiến ​​trúc CPU mà bạn đang làm việc. Có rất nhiều sự hiểu biết ngầm về kiến ​​trúc của một máy vi tính (thường làmáy vi tính bạn đang làm việc) khi lập trình trong C mà đơn giản là không có mặt hoặc không cần thiết khi lập trình trong một cái gì đó như C # hoặc Java. Tất cả thông tin đó đã được tải xuống cho trình lập trình biên dịch (hoặc VM).


"Vấn đề phần cứng nhiều hơn" chỉ hoạt động trong môi trường thực sự có thể. Thị trường nhúng là một ví dụ hoàn hảo (và đó là một thị trường lớn ).
Bob Bolog

Blog của Jeff và Joel chỉ nói về các hệ thống kinh doanh, không phải các hệ thống nhúng, vì vậy thật hợp lý khi cho rằng đó là bối cảnh mà câu hỏi này được hỏi.
Robert C. Barth

1) .net code chạy nhanh như mã C? Bạn đã bao giờ thực sự viết một chương trình C? 2) Tâm lý "ném thêm phần cứng vào vấn đề" là lý do tại sao máy 2GB lõi kép 1,3 GHz của tôi hầu như không thể theo kịp Windows XP trong khi máy 512MB 512 MHz của tôi bay với phiên bản Ubuntu mới nhất.
Robert Gamble

Vâng, tôi đã viết C. Nó không vẻ vang như mọi người nghĩ. Và các dự án chi phí quá nhiều. Đó là một trường hợp đơn giản về kinh tế. Tôi đã chạy Win2k trên Pentium Pro 180 MHz với 768MB RAM trong nhiều năm dưới dạng thư và máy chủ web. Nó chạy tốt Bằng chứng giai thoại có nghĩa là không có gì.
Robert C. Barth

C không "vẻ vang" nhưng rất nhanh, tôi đã viết đủ mã C và C # để biết rằng C hầu như luôn nhanh hơn C # rất nhiều trong khi thực hiện cùng một nhiệm vụ. Đối với một số tác vụ, phải mất nhiều thời gian để phát triển hơn các ngôn ngữ cấp cao hơn nhưng tất cả chỉ là sử dụng công cụ phù hợp cho công việc và đôi khi C là nó.
Robert Gamble

1

Đó là sự khác biệt giữa tự động và thủ công, ngôn ngữ cấp cao hơn là trừu tượng do đó tự động. C / C ++ được điều khiển và xử lý thủ công, thậm chí mã kiểm tra lỗi đôi khi là lao động thủ công.

C và C ++ cũng là các ngôn ngữ được biên dịch, có nghĩa là không có ngôn ngữ nào hoạt động ở mọi nơi, các ngôn ngữ này phải được tinh chỉnh cho phần cứng bạn làm việc với do đó thêm một lớp gotcha bổ sung. Mặc dù hiện tại điều này hơi khó hiểu vì trình biên dịch C / C ++ đang trở nên phổ biến hơn trên tất cả các nền tảng. Bạn có thể thực hiện các phần tổng hợp chéo giữa các nền tảng. Đây vẫn không phải là tình huống chạy ở mọi nơi, về cơ bản, trình biên dịch A của bạn sẽ biên dịch theo trình biên dịch B cùng mã với kiến ​​trúc khác nhau.

Các ngôn ngữ C dòng dưới cùng không có nghĩa là dễ hiểu hoặc lý do, đây cũng là lý do tại sao chúng được gọi là ngôn ngữ hệ thống. Họ đi ra trước tất cả những điều vô nghĩa trừu tượng cấp cao này. Đây cũng là lý do tại sao chúng không được sử dụng cho lập trình web front end. Họ chỉ không phù hợp với nhiệm vụ, ý nghĩa của họ để giải quyết các vấn đề phức tạp không thể giải quyết bằng công cụ ngôn ngữ thông thường.

Đây là lý do tại sao bạn có được những thứ điên rồ như (kiến trúc vi mô, trình điều khiển, vật lý lượng tử, Trò chơi AAA, hệ điều hành) có những thứ C và C ++ rất phù hợp. Tốc độ và số giòn là lĩnh vực chính.



1

Có nhiều lý do, bao gồm:

  • Nó biên dịch thành ngôn ngữ lắp ráp.
  • Nó được gõ tĩnh.
  • Không thu gom rác.
  • Không xử lý lỗi.
  • Nhiều ngôn ngữ lập trình thêm các tính năng mới. Một phần trong triết lý của C là giữ mọi thứ đơn giản thay vì thêm nhiều tính năng.

Tại sao nó phải nhanh hơn bởi vì nó không phải là đối tượng gốc?
sb27

A) lập trình hướng đối tượng tạo ra nhu cầu thu gom rác, B) các tính năng lớn như lập trình hướng đối tượng làm tăng thêm độ phức tạp cho trình biên dịch,
Sapphire_Brick

A) Không. Xem C ++ hoặc Rust. B) Có, nhưng nó cũng mang đến cho Trình biên dịch cơ hội tối ưu hóa mới.
sb27

A) Rust có bộ sưu tập rác thời gian biên dịch và c ++ có bộ sưu tập rác cho các lớp, đó là lý do tại sao nó có hàm hủy, B) độ phức tạp được tối ưu hóa vẫn còn phức tạp
Sapphire_Brick

A) Không phải là thu gom rác, việc quản lý bộ nhớ phải được thực hiện ngay cả khi bạn thực hiện chương trình của mình trong hội đồng B) Không. Trừu tượng hơn cho phép trình tối ưu hóa đưa ra các giả định tốt hơn.
sb27
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.