Làm thế nào một ngôn ngữ có trình biên dịch được viết bằng C có thể nhanh hơn C?


175

Nhìn vào trang web của Julia , bạn có thể thấy một số điểm chuẩn của một số ngôn ngữ trên một số thuật toán (thời gian hiển thị bên dưới). Làm thế nào một ngôn ngữ với trình biên dịch ban đầu được viết bằng C, vượt trội hơn mã C?

nhập mô tả hình ảnh ở đây Hình: thời gian chuẩn so với C (nhỏ hơn là tốt hơn, hiệu suất C = 1.0).



382
Làm thế nào một chiếc xe, một vật thể nhân tạo, có thể di chuyển nhanh hơn một người đàn ông?
babou

19
Theo bảng, Python chậm hơn C. Bạn có nghĩ rằng không thể viết trình biên dịch C trong Python tạo mã giống như trình biên dịch C yêu thích của bạn không? Và ngôn ngữ nào được viết bằng cách nào?
Carsten S

6
Nhận xét của babou là đúng chỗ, nhưng tôi không nghĩ chúng ta cần nhiều phiên bản giống nhau.
Raphael

14
Một suy nghĩ liên quan. Nhiều trình biên dịch tự lưu trữ , có nghĩa là chúng được viết bằng ngôn ngữ riêng của chúng (thường cộng với một số phần lắp ráp) và được biên dịch với phiên bản trước đó của chính nó. Tuy nhiên, trình biên dịch trở nên tốt hơn và nhanh hơn. Tâm thổi .
Schwern

Câu trả lời:


263

Không có mối quan hệ cần thiết giữa việc thực hiện trình biên dịch và đầu ra của trình biên dịch. Bạn có thể viết một trình biên dịch trong một ngôn ngữ như Python hay Ruby, mà hầu hết các trường phổ biến là rất chậm, và trình biên dịch có thể sản lượng cao được tối ưu hóa mã máy có khả năng đạt vượt C. Trình biên dịch riêng của mình sẽ mất nhiều thời gian để chạy, vì mã được viết bằng một ngôn ngữ chậm. (Nói chính xác hơn, được viết bằng một ngôn ngữ có triển khai chậm. Ngôn ngữ không thực sự nhanh hay chậm, như Raphael đã chỉ ra trong một bình luận. Tôi mở rộng về ý tưởng này bên dưới.) Chương trình được biên dịch sẽ nhanh như nó Việc triển khai riêng cho phép chúng tôi có thể viết một trình biên dịch bằng Python tạo mã máy giống như trình biên dịch Fortran và các chương trình được biên dịch của chúng tôi sẽ nhanh như Fortran, mặc dù chúng sẽ mất nhiều thời gian để biên dịch.

Đó là một câu chuyện khác nếu chúng ta nói về một thông dịch viên. Các thông dịch viên phải được chạy trong khi chương trình họ đang phiên dịch đang chạy, do đó, có một mối liên hệ giữa ngôn ngữ mà trình thông dịch được triển khai và hiệu suất của mã thông dịch. Phải có một số tối ưu hóa thời gian chạy thông minh để tạo ra một ngôn ngữ diễn giải chạy nhanh hơn ngôn ngữ mà trình thông dịch được triển khai và hiệu suất cuối cùng có thể phụ thuộc vào mức độ phù hợp của loại mã này đối với loại tối ưu hóa này. Nhiều ngôn ngữ, chẳng hạn như Java và C #, sử dụng thời gian chạy với mô hình kết hợp kết hợp một số lợi ích của trình thông dịch với một số lợi ích của trình biên dịch.

Để làm ví dụ cụ thể, chúng ta hãy xem xét kỹ hơn về Python. Python có một số triển khai. Phổ biến nhất là CPython, một trình thông dịch mã byte được viết bằng C. Ngoài ra còn có PyPy, được viết bằng một phương ngữ chuyên biệt của Python có tên là RPython và sử dụng mô hình biên dịch lai giống như JVM. PyPy nhanh hơn nhiều so với CPython trong hầu hết các điểm chuẩn; nó sử dụng tất cả các loại thủ thuật tuyệt vời để tối ưu hóa mã khi chạy. Tuy nhiên, ngôn ngữ Python mà PyPy chạy chính xác là cùng ngôn ngữ Python mà CPython chạy, loại bỏ một số khác biệt không ảnh hưởng đến hiệu suất.

Giả sử chúng ta đã viết một trình biên dịch bằng ngôn ngữ Python cho Fortran. Trình biên dịch của chúng tôi tạo ra mã máy giống như GFortran. Bây giờ chúng tôi biên dịch một chương trình Fortran. Chúng tôi có thể chạy trình biên dịch của mình trên CPython hoặc chúng tôi có thể chạy nó trên PyPy, vì nó được viết bằng Python và cả hai triển khai này đều chạy cùng một ngôn ngữ Python. Những gì chúng ta sẽ tìm thấy là nếu chúng ta chạy trình biên dịch của mình trên CPython, sau đó chạy nó trên PyPy, sau đó biên dịch cùng một nguồn Fortran với GFortran, chúng ta sẽ nhận được chính xác cùng một mã máy cả ba lần, vì vậy chương trình được biên dịch sẽ luôn chạy ở cùng tốc độ. Tuy nhiên, thời gian cần thiết để sản xuất chương trình biên dịch đó sẽ khác nhau. CPython nhiều khả năng sẽ mất nhiều thời gian hơn PyPy và PyPy nhiều khả năng sẽ mất nhiều thời gian hơn so với GFortran, mặc dù cuối cùng tất cả chúng sẽ xuất ra cùng một mã máy.

Từ việc quét bảng điểm chuẩn của trang web Julia, có vẻ như không có ngôn ngữ nào chạy trên trình thông dịch (Python, R, Matlab / Octave, Javascript) có bất kỳ điểm chuẩn nào mà chúng đánh bại C. Điều này thường phù hợp với những gì tôi mong đợi, mặc dù tôi có thể tưởng tượng mã được viết bằng thư viện Numpy được tối ưu hóa cao của Python (viết bằng C và Fortran) đánh bại một số triển khai C có thể có của mã tương tự. Các ngôn ngữ bằng hoặc tốt hơn C đang được biên dịch (Fortran, Julia ) hoặc sử dụng mô hình kết hợp với biên dịch một phần (Java và có thể là LuaJIT). PyPy cũng sử dụng mô hình lai, do đó, hoàn toàn có thể nếu chúng tôi chạy cùng mã Python trên PyPy thay vì CPython, chúng tôi thực sự sẽ thấy nó đánh bại C trên một số điểm chuẩn.


9
Đây là một câu trả lời tuyệt vời. Rất rõ ràng, dễ hiểu và nhiều thông tin. Cảm ơn bạn rất nhiều vì đã dành thời gian để viết nó!
Alex A.

7
Cả javascript và java đều đang được chạy với trình biên dịch JIT, tuy nhiên java có một bài kiểm tra nhanh hơn C. Lý do lớn nhất khiến trình chạy / trình biên dịch có thể chạy nhanh hơn là do có nhiều thông tin hơn. Trình biên dịch C / C ++ có thể tối ưu hóa mã (thường) nhiều hơn sau đó có người viết lắp ráp bằng tay, đơn giản vì trình biên dịch có nhiều thông tin có sẵn cho nó. Chắc chắn, về mặt lý thuyết, người đó có thể viết mã lắp ráp tốt hơn, nhưng điều đó đòi hỏi nhiều kiến ​​thức và kỹ năng hơn thì hầu hết mọi người đều có. Ngôn ngữ có thể mở rộng hơn về điều này, có thể tối ưu hóa cho máy chính xác đang chạy trên đó
Chương trình

Những gì tối ưu hóa trình biên dịch làm là một điều quan trọng cần xem xét. Một trình biên dịch thực sự thông minh sẽ nhận ra rằng chương trình là điểm chuẩn tổng hợp và chỉ cần tối ưu hóa tất cả mã, chỉ cần tạo đầu ra mong đợi.
ghellquist

@ghellquist Chắc chắn, nếu điểm chuẩn là đủ nhân tạo và trình biên dịch đủ thông minh. Tuy nhiên, điều đó không liên quan trực tiếp hoặc trực tiếp đến ngôn ngữ triển khai của nhà soạn nhạc, vì vậy tôi đã không đề cập đến nó ở đây.
tsleyon

97

Làm thế nào một cỗ máy được chế tạo bởi một người đàn ông mạnh hơn một người đàn ông? Đây chính xác là cùng một câu hỏi.

Câu trả lời là đầu ra của trình biên dịch phụ thuộc vào các thuật toán được thực hiện bởi trình biên dịch đó, chứ không phụ thuộc vào ngôn ngữ được sử dụng để thực hiện nó. Bạn có thể viết một trình biên dịch thực sự chậm, không hiệu quả, tạo ra mã rất hiệu quả. Không có gì đặc biệt về trình biên dịch: nó chỉ là một chương trình lấy một số đầu vào và tạo ra một số đầu ra.


33
Làm thế nào một chương trình cờ vua có thể đánh bại con người đã viết nó?
Thorbjørn Ravn Andersen

25
Bằng cách di chuyển tốt hơn! <rimshot>
Tony Enni

Để diễn giải câu trả lời của Penn Gilette về lý do tại sao máy tính không thể đánh bại một người đàn ông trong cờ vua: "Bạn có mong đợi một robot được thiết kế bởi GE sẽ thua một người đàn ông trong trận đấu quyền anh không?"
Dave Kanter

90

Tôi muốn đưa ra một quan điểm chống lại một giả định chung, theo ý kiến ​​của tôi, sai lầm đến mức có hại khi chọn công cụ cho công việc.

Không có thứ gọi là ngôn ngữ chậm hay nhanh. ¹

Trên đường đến CPU thực sự đang làm gì đó, có nhiều bước².

  1. Ít nhất một lập trình viên với các kỹ năng nhất định.
  2. Ngôn ngữ (chính thức) mà họ lập trình bằng ("mã nguồn").
  3. Các thư viện họ sử dụng.
  4. Một cái gì đó dịch mã nguồn thành mã máy (trình biên dịch, thông dịch viên).
  5. Kiến trúc phần cứng tổng thể, ví dụ số lượng đơn vị xử lý và bố cục của hệ thống phân cấp bộ nhớ.
  6. Hệ điều hành quản lý phần cứng.
  7. Tối ưu hóa trên CPU.

Mỗi mục duy nhất đóng góp vào thời gian chạy thực tế mà bạn có thể đo lường, đôi khi rất nhiều. "Ngôn ngữ" khác nhau tập trung vào những thứ khác nhau³.

Chỉ để đưa ra một số ví dụ.

  • 1 so với 2-4 : một lập trình viên C trung bình có khả năng tạo mã kém hơn nhiều so với lập trình viên Java trung bình, cả về tính chính xác và hiệu quả. Đó là bởi vì lập trình viên có nhiều trách nhiệm hơn trong C.

  • 1/4 so với 7 : trong ngôn ngữ cấp thấp như C, bạn có thể khai thác một số tính năng CPU nhất định với tư cách là một lập trình viên . Trong các ngôn ngữ cấp cao hơn, chỉ có trình biên dịch / trình thông dịch có thể làm như vậy và chỉ khi họ biết CPU mục tiêu.

  • 1/4 so với 5 : bạn muốn hoặc phải điều khiển bố cục bộ nhớ để sử dụng tốt nhất kiến ​​trúc bộ nhớ trong tay? Một số ngôn ngữ cho phép bạn kiểm soát điều đó, một số ngôn ngữ thì không.

  • 2/4 so với 3 : Bản thân Python được giải thích rất chậm, nhưng có những ràng buộc phổ biến đối với các thư viện được biên dịch nguyên bản, được tối ưu hóa cao cho máy tính khoa học. Vì vậy, cuối cùng thực hiện một số điều trong Python là nhanh , nếu hầu hết các công việc được thực hiện bởi các thư viện này.

  • 2 vs 4 : Trình thông dịch Ruby tiêu chuẩn khá chậm. JRuby, mặt khác, có thể rất nhanh. Đó là cùng một ngôn ngữ là nhanh chóng bằng cách sử dụng trình biên dịch / trình thông dịch khác.

  • 1/2 so với 4 : Sử dụng tối ưu hóa trình biên dịch, mã đơn giản có thể được dịch thành mã máy rất hiệu quả.

Điểm mấu chốt là, điểm chuẩn bạn tìm thấy không có nhiều ý nghĩa, ít nhất là khi được đưa vào bảng mà bạn đưa vào. Ngay cả khi tất cả những gì bạn quan tâm là thời gian chạy, bạn cần chỉ định toàn bộ chuỗi từ lập trình viên đến CPU; hoán đổi bất kỳ yếu tố nào có thể thay đổi kết quả đáng kể.

Để rõ ràng, điều này trả lời câu hỏi bởi vì nó cho thấy rằng ngôn ngữ mà trình biên dịch (bước 4) được viết ra chỉ là một phần của câu đố và có lẽ không liên quan gì cả (xem các câu trả lời khác).


  1. Chắc chắn các tính năng ngôn ngữ tốn kém hơn để thực hiện so với các tính năng khác. Nhưng sự tồn tại của các tính năng không có nghĩa là bạn phải sử dụng chúng và một tính năng đắt tiền có thể tiết kiệm việc sử dụng nhiều tính năng rẻ hơn và do đó cuối cùng phải trả tiền. (Có những lợi thế khác không thể đo lường được trong thời gian chạy.)
  2. Tôi bỏ qua cấp độ thuật toán bởi vì nó không phải lúc nào cũng áp dụng và chủ yếu độc lập với ngôn ngữ lập trình được sử dụng. Hãy nhớ rằng các thuật toán khác nhau cho vay tốt hơn cho phần cứng khác nhau, ví dụ.
  3. Tôi cố tình không đi vào các số liệu thành công khác nhau ở đây: hiệu quả thời gian chạy, hiệu quả bộ nhớ, thời gian của nhà phát triển, bảo mật, an toàn, tính chính xác (có thể chứng minh?), Hỗ trợ công cụ, độc lập nền tảng, ...

    So sánh các ngôn ngữ với một số liệu mặc dù chúng được thiết kế cho các mục tiêu hoàn toàn khác nhau là một sai lầm lớn.


1
@babou Đồng ý, giải thích rất hay. Vì vậy, điều gì sẽ là một số liệu tốt hơn, hoặc có lẽ là tập hợp các số liệu , có thể được sử dụng để so sánh các ngôn ngữ với trình biên dịch / trình thông dịch tương ứng của chúng? Ngoài ra, một nitlog nhỏ: bạn nói "Không có thứ gọi là ngôn ngữ chậm hay nhanh" và sau đó "Bản thân Python chậm kinh khủng", nhưng tôi cho rằng bạn có nghĩa là trình thông dịch Python.
StrugglingProgrammer

2
@benalbrecht Quan điểm của tôi là không có bộ số liệu tốt như vậy. Đó là một sự đánh đổi, luôn luôn. Nếu bạn xây dựng trình điều khiển thiết bị, bạn muốn chính xác hơn tất cả mọi thứ. Nếu bạn xây dựng xương sống của Twitter, bạn muốn hiệu quả hơn tất cả. Trong cả hai trường hợp, bạn sử dụng các công cụ và thuê những người cho phép điều đó. Nếu bạn là một người khởi nghiệp ứng dụng Android, bạn sử dụng những gì mọi người biết và / hoặc những gì giảm thiểu thời gian tiếp thị của bạn. Nếu bạn dạy các thuật toán, bạn muốn có một ngôn ngữ với cú pháp ngắn gọn, rõ ràng và bản tóm tắt nhỏ. Và như vậy. Ưu tiên khác nhau, và vì vậy chúng tôi có ngôn ngữ khác nhau.
Raphael


23

Có một điều bị lãng quên về tối ưu hóa ở đây.

Đã có cuộc tranh luận lâu dài về fortran vượt trội hơn C. Đặt ra cuộc tranh luận không đúng định dạng: cùng một mã được viết bằng C và fortran (như người kiểm tra nghĩ) và hiệu suất đã được kiểm tra dựa trên cùng một dữ liệu. Vấn đề là, các ngôn ngữ này khác nhau, C cho phép con trỏ răng cưa, trong khi fortran thì không.

Vì vậy, các mã không giống nhau, không có __restrict trong các tệp được kiểm tra C, điều này mang lại sự khác biệt, sau khi viết lại các tệp để nói với trình biên dịch rằng nó có thể tối ưu hóa con trỏ, thời gian chạy trở nên tương tự.

Vấn đề ở đây là, một số kỹ thuật tối ưu hóa dễ dàng hơn (hoặc bắt đầu hợp pháp) trong ngôn ngữ mới được tạo.


X

Thứ hai VM có thể thực hiện kiểm tra áp suất trong khi chạy, do đó, nó có thể lấy mã áp lực và tối ưu hóa nó hoặc thậm chí tính toán trước trong thời gian chạy. Chương trình C được biên dịch trước không mong đợi áp lực ở đâu hoặc (phần lớn thời gian) có các phiên bản chung của các tệp thực thi cho dòng máy nói chung.

Trong thử nghiệm này cũng có JS, cũng có VM nhanh hơn V8 và nó cũng hoạt động nhanh hơn C trong một số thử nghiệm.

Tôi đã kiểm tra nó và có những kỹ thuật tối ưu hóa độc đáo chưa có trong trình biên dịch C.

Trình biên dịch C sẽ phải thực hiện phân tích tĩnh toàn bộ mã cùng một lúc, diễu hành trên nền tảng nhất định và giải quyết các vấn đề liên kết bộ nhớ.

VM chỉ phiên âm một phần mã để tối ưu hóa lắp ráp và chạy nó.

Về Julia - khi tôi kiểm tra nó hoạt động trên AST của mã, ví dụ GCC đã bỏ qua bước này và gần đây mới bắt đầu lấy một số thông tin từ đó. Điều này cộng với các ràng buộc khác và các kỹ thuật VM có thể giải thích một chút.

Ví dụ: chúng ta hãy thực hiện vòng lặp đơn giản, lấy điểm kết thúc bắt đầu từ các biến và tải một phần biến vào các phép tính biết trong thời gian chạy.

Trình biên dịch C tạo các biến tải từ các thanh ghi.
Nhưng trong thời gian chạy, các biến này được biết và được coi là hằng số thông qua thực thi.
Vì vậy, thay vì tải các biến từ các thanh ghi (và không thực hiện bộ đệm vì nó có thể thay đổi và từ phân tích tĩnh thì không rõ) chúng được xử lý hoàn toàn giống như các hằng số và được gấp lại, lan truyền.


12

Các câu trả lời trước đưa ra khá nhiều lời giải thích, mặc dù chủ yếu là từ góc độ thực dụng, cũng như câu hỏi có ý nghĩa , như được giải thích một cách xuất sắc bởi câu trả lời của Raphael .

Thêm vào câu trả lời này, chúng ta nên lưu ý rằng, ngày nay, trình biên dịch C được viết bằng C. Tất nhiên, như Raphael lưu ý, đầu ra của chúng và hiệu năng của nó có thể phụ thuộc, trong số những thứ khác, vào CPU mà nó đang chạy. Nhưng nó cũng phụ thuộc vào số lượng tối ưu hóa được thực hiện bởi trình biên dịch. Nếu bạn viết bằng C một trình biên dịch tối ưu hóa tốt hơn cho C (sau đó bạn biên dịch với trình biên dịch cũ để có thể chạy nó), bạn sẽ có một trình biên dịch mới làm cho C trở thành ngôn ngữ nhanh hơn trước đây. Vậy, tốc độ của C là bao nhiêu? Lưu ý rằng bạn thậm chí có thể biên dịch trình biên dịch mới với chính nó, như một lần chuyển thứ hai, để nó biên dịch hiệu quả hơn, mặc dù vẫn đưa ra cùng một mã đối tượng. Và định lý việc làm đầy đủ cho thấy rằng họ không có kết thúc với những cải tiến như vậy (nhờ Raphael cho con trỏ).

Nhưng tôi nghĩ rằng nó có thể đáng để cố gắng chính thức hóa vấn đề, vì nó minh họa rất rõ một số khái niệm cơ bản, và đặc biệt là quan điểm đối nghịch với hoạt động của mọi thứ.

Trình biên dịch là gì?

CSTCCSTP:SP SP:T TP

CSTCST{(P:S,P:T)PSSPTT}

CSTPSPTP

P:TP:SCST

Tinh chỉnh đối số, có lẽ chúng ta muốn trình biên dịch có hiệu quả tốt, để việc dịch có thể được thực hiện trong thời gian hợp lý. Vì vậy, hiệu suất của chương trình biên dịch quan trọng đối với người dùng, nhưng nó không có tác động đến ngữ nghĩa. Tôi đang nói hiệu suất, bởi vì độ phức tạp về mặt lý thuyết của một số trình biên dịch có thể cao hơn nhiều so với mong đợi.

Giới thiệu về bootstrapping

Điều này sẽ minh họa sự khác biệt, và hiển thị một ứng dụng thực tế.

SISCST:SSCST:SISP:SP:TST

CST:SSCST:TTTT


"Điều quan trọng về mặt ngữ nghĩa là những gì được thực hiện, chứ không phải làm thế nào (và nhanh như thế nào) được thực hiện" - nó đề cập rằng các tiêu chí phi chức năng tồn tại trong thực tế. Có nhiều chương trình mục tiêu tương đương về chức năng nhưng chúng tôi có thể thích một số chương trình khác vì một số lý do (hiệu quả, kích thước, căn chỉnh bộ nhớ tốt hơn, ...). Điều đó có nghĩa là, khung nhìn của trình biên dịch là một hàm như bạn định nghĩa bị hạn chế hơn chúng ta muốn (nó cũng thường bỏ qua các hiệu ứng phụ, ví dụ I / O). Nó phục vụ mục đích giải thích mà bạn muốn, mặc dù.
Raphael

@Raphael Liên quan đến định lý việc làm đầy đủ, tôi đã nghĩ đến điều đó (trong nhận xét của tôi về C), nhưng tôi không biết tên và hoãn tìm một tài liệu tham khảo. Cảm ơn đã làm điều đó. --- Ngữ nghĩa mà tôi nói đến là của trình biên dịch, không phải của chương trình đích. Chương trình mục tiêu được bảo tồn theo cú pháp và hoạt động, không chỉ về mặt ngữ nghĩa. Hoặc tôi đã hiểu nhầm nhận xét của bạn. Tôi chỉnh sửa để làm cho mọi thứ chính xác hơn trong văn bản của tôi.
babou

@Raphael Vì bạn không xóa bình luận của mình, điều đó có nghĩa là tôi đã hiểu nhầm hoặc không trả lời đúng? Làm thế nào mà khung nhìn của trình biên dịch (không phải của chương trình được biên dịch) như là một hàm quá hạn chế, từ quan điểm ngữ nghĩa. Tất nhiên, là một hàm, nó có thể lấy các đối số khác ngoài chương trình được biên dịch, chẳng hạn như các chỉ thị tối ưu hóa) nhưng đây là một chi tiết sẽ không thay đổi cuộc thảo luận.
babou

Tôi nghĩ nhận xét của tôi là một con trỏ hướng tới "có nhiều hơn mô hình này". Những gì bạn viết không sai, nhưng nó không phải là tất cả. Về mặt lý thuyết, điều này dường như rõ ràng: "" chức năng biên dịch không phải là cho mỗi gia nhập rõ ràng kể từ khi có được vô cùng nhiều chương trình mục tiêu có thể, tất cả các ngữ nghĩa tương đương. Chọn để chọn là một phần rất quan trọng của thiết kế trình biên dịch.
Raphael

CP

6

Theo định lý tăng tốc của Blum, có những chương trình được viết và chạy trên tổ hợp máy tính / trình biên dịch nhanh nhất sẽ chạy chậm hơn chương trình tương tự trên PC đầu tiên của bạn đang chạy BASIC. Không có "ngôn ngữ nhanh nhất". Tất cả những gì bạn có thể nói là nếu bạn viết cùng một thuật toán bằng nhiều ngôn ngữ (triển khai; như đã lưu ý, có rất nhiều trình biên dịch C khác nhau và tôi thậm chí đã bắt gặp một trình thông dịch C có khả năng khá cao), nó sẽ chạy nhanh hơn hoặc chậm hơn trong mỗi ngôn ngữ .

Không thể có một hệ thống phân cấp "luôn luôn chậm hơn". Đây là một hiện tượng mà mọi người thông thạo một số ngôn ngữ đều biết: Mỗi ngôn ngữ lập trình được thiết kế cho một loại ứng dụng cụ thể và các triển khai được sử dụng nhiều hơn đã được tối ưu hóa một cách đáng yêu cho loại chương trình đó. Tôi khá chắc chắn rằng, ví dụ, một chương trình đánh lừa các chuỗi được viết bằng Perl có thể sẽ đánh bại cùng một thuật toán được viết bằng C, trong khi một chương trình nhai các mảng số nguyên lớn trong C sẽ nhanh hơn Perl.


1
"Mỗi ngôn ngữ lập trình được thiết kế cho một loại ứng dụng cụ thể" Trên thực tế, hầu hết các ngôn ngữ lập trình mà mọi người thực sự sử dụng là ngôn ngữ có mục đích chung, ngược lại với việc được thiết kế cho các ứng dụng cụ thể. Chỉ là một số ngôn ngữ cuối cùng được sử dụng nhiều hơn trong một số lĩnh vực nhất định chủ yếu là do hiệu ứng xã hội.
Khối

Tôi đoán nó phụ thuộc vào mức độ bạn diễn giải thuật ngữ "loại ứng dụng cụ thể". Mặc dù sự thật là hầu hết các ngôn ngữ chính không phải là DSL, nhưng chắc chắn chúng được thiết kế với những mục đích sử dụng nhất định. C được thiết kế để thực hiện Unix. Java được thiết kế để kịch bản TV tương tác. Smalltalk được thiết kế để dạy trẻ em. ECMAScript được thiết kế cho kịch bản web phía máy chủ và phía máy khách. Perl được thiết kế để xử lý văn bản và kịch bản Unix. PHP được thiết kế cho kịch bản web phía máy chủ. Erlang được thiết kế cho độ tin cậy. Lược đồ được thiết kế để khám phá các trận đấu
Jörg W Mittag

Nền tảng của OO và Mô hình diễn viên. APL được thiết kế như một ký hiệu cho việc dạy toán. Julia được thiết kế để lập trình khoa học. Tất cả các ngôn ngữ đó hiện đang được sử dụng bên ngoài miền vấn đề ban đầu của chúng, nhưng vẫn còn một số thuộc tính trong các ngôn ngữ đó làm cho chúng phù hợp hơn hoặc kém hơn đối với một số loại ứng dụng, mặc dù chúng đều có thể được sử dụng để xây dựng tất cả các loại nhiều thứ.
Jörg W Mittag

4

Chúng ta hãy quay trở lại dòng ban đầu: "Làm thế nào một ngôn ngữ có trình biên dịch được viết bằng C có thể nhanh hơn C?" Tôi nghĩ điều này thực sự có ý muốn nói: làm thế nào một chương trình được viết bằng Julia, có cốt lõi được viết bằng C, có thể nhanh hơn một chương trình được viết bằng C? Cụ thể, làm thế nào chương trình "mandel" như được viết bằng Julia có thể chạy trong 87% thời gian thực hiện của chương trình "mandel" tương đương được viết bằng C?

Chuyên luận của Babou là câu trả lời đúng duy nhất cho câu hỏi này cho đến nay. Tất cả các câu trả lời khác cho đến nay đều ít nhiều trả lời các câu hỏi khác. Vấn đề với văn bản của babou là phần mô tả lý thuyết dài nhiều đoạn của "Trình biên dịch là gì" được viết theo thuật ngữ mà người đăng ban đầu có thể sẽ gặp khó khăn trong việc hiểu. Bất cứ ai nắm bắt được các khái niệm được gọi bằng các từ "ngữ nghĩa", "biểu thị", "hiện thực hóa", "tính toán" và như vậy sẽ biết câu trả lời cho câu hỏi.

Câu trả lời đơn giản hơn là cả mã C, cũng không phải mã Julia đều được máy thực thi trực tiếp. Cả hai đều phải được dịch và quá trình dịch thuật đó đưa ra rất nhiều cách mà mã máy thực thi có thể chậm hơn hoặc nhanh hơn, nhưng vẫn tạo ra kết quả cuối cùng. Cả C và Julia đều biên soạn, có nghĩa là một loạt các bản dịch sang dạng khác. Thông thường, một tệp văn bản có thể đọc được của con người được dịch sang một số biểu diễn bên trong và sau đó được viết ra dưới dạng một chuỗi các hướng dẫn mà máy tính có thể hiểu trực tiếp. Với một số ngôn ngữ, có nhiều thứ hơn thế và Julia là một trong số đó - nó có trình biên dịch "JIT", có nghĩa là toàn bộ quá trình dịch thuật không phải xảy ra cùng một lúc cho toàn bộ chương trình. Nhưng kết quả cuối cùng cho bất kỳ ngôn ngữ nào là mã máy không cần dịch thêm, mã có thể được gửi trực tiếp đến CPU để làm cho nó làm một cái gì đó. Cuối cùng, ĐÂY là "tính toán" và có nhiều cách để nói với CPU cách nhận câu trả lời bạn muốn.

Người ta có thể tưởng tượng một ngôn ngữ lập trình có cả toán tử "cộng" và "nhân" và một ngôn ngữ khác chỉ có "cộng". Nếu tính toán của bạn yêu cầu nhân, một ngôn ngữ sẽ "chậm hơn" vì tất nhiên CPU có thể thực hiện cả hai cách trực tiếp, nhưng nếu bạn không có cách nào để diễn đạt nhu cầu nhân 5 * 5, bạn sẽ phải viết "5 + 5 + 5 + 5 + 5 ". Sau này sẽ mất nhiều thời gian hơn để đi đến cùng một câu trả lời. Có lẽ, có một số điều này xảy ra với Julia; có lẽ ngôn ngữ cho phép lập trình viên nêu ra mục tiêu mong muốn là tính toán một bộ Mandelbrot theo cách không thể diễn đạt trực tiếp trong C.

Bộ xử lý được sử dụng cho điểm chuẩn được liệt kê là CPU Xeon E7-8850 2.00GHz. Điểm chuẩn C đã sử dụng trình biên dịch gcc 4.8.2 để tạo hướng dẫn cho CPU đó, trong khi Julia sử dụng khung trình biên dịch LLVM. Có thể là phần phụ trợ của gcc (phần tạo mã máy cho kiến ​​trúc CPU cụ thể) không tiên tiến theo cách nào đó như phần phụ trợ LLVM. Điều đó có thể làm cho một sự khác biệt trong hiệu suất. Ngoài ra còn có nhiều thứ khác đang diễn ra - trình biên dịch có thể "tối ưu hóa" bằng cách có thể đưa ra các hướng dẫn theo một thứ tự khác với chỉ định của lập trình viên, hoặc thậm chí không làm một số điều nếu nó có thể phân tích mã và xác định chúng không phải là cần thiết để có được câu trả lời đúng Và lập trình viên có thể đã viết một phần của chương trình C theo cách làm cho nó chậm, nhưng không

Tất cả đều là những cách nói: có rất nhiều cách để viết mã máy để tính toán một bộ Mandelbrot và ngôn ngữ bạn sử dụng có ảnh hưởng lớn đến cách viết mã máy đó. Bạn càng hiểu về biên dịch, bộ hướng dẫn, bộ nhớ cache, v.v., bạn sẽ được trang bị tốt hơn để có được kết quả bạn muốn. Điểm nổi bật của các kết quả điểm chuẩn được trích dẫn cho Julia là không có ngôn ngữ hay công cụ nào là tốt nhất trong mọi thứ. Trong thực tế, yếu tố tốc độ tốt nhất trong toàn bộ biểu đồ là dành cho Java!


2

Tốc độ của một chương trình được biên dịch phụ thuộc vào hai điều:

  1. Các đặc tính hiệu suất của máy thực hiện nó
  2. Nội dung của tập tin thực thi

Ngôn ngữ mà trình biên dịch được viết bằng không liên quan đến (1). Ví dụ, một trình biên dịch Java có thể được viết bằng C hoặc Java hoặc Python, nhưng trong mọi trường hợp, "máy" thực thi chương trình là JVM.

Ngôn ngữ mà trình biên dịch được viết bằng không liên quan đến (2). Ví dụ, không có lý do tại sao trình biên dịch C được viết bằng Python không thể xuất chính xác cùng một tệp thực thi như trình biên dịch C được viết bằng C hoặc Java.


1

Tôi sẽ cố gắng đưa ra một câu trả lời ngắn hơn.

Cốt lõi của câu hỏi nằm trong định nghĩa "tốc độ" của ngôn ngữ .

Hầu hết nếu không phải tất cả các bài kiểm tra so sánh tốc độ thì không kiểm tra tốc độ tối đa có thể là bao nhiêu. Thay vào đó họ viết một chương trình nhỏ bằng ngôn ngữ mà họ muốn kiểm tra, để giải quyết vấn đề. Khi viết chương trình, lập trình viên sử dụng những gì họ cho là * để thực hành tốt nhất và quy ước về ngôn ngữ, tại thời điểm kiểm tra. Sau đó, họ đo tốc độ thực hiện chương trình.

* Các giả định đôi khi sai.


0

Mã được viết bằng ngôn ngữ X có Trình biên dịch được viết bằng C, có thể vượt trội hơn mã được viết bằng C, được cung cấp, trình biên dịch C không tối ưu hóa kém so với ngôn ngữ X. Nếu chúng ta tiếp tục tối ưu hóa thảo luận thì nếu trình biên dịch X có thể tạo ra tốt hơn mã đối tượng được tạo bởi trình biên dịch C, sau đó mã được viết bằng X có thể giành chiến thắng trong cuộc đua.

Nhưng nếu ngôn ngữ X là ngôn ngữ được thông dịch và trình thông dịch được viết bằng C và nếu chúng ta giả sử rằng trình thông dịch của ngôn ngữ X và mã được viết bằng C được biên dịch bởi cùng một trình biên dịch C, thì không có cách nào mã được viết bằng X sẽ vượt trội hơn mã được viết bằng C, với điều kiện cả hai thực hiện theo cùng một thuật toán và sử dụng các cấu trúc dữ liệu tương đương.


2
Điều này thêm gì vào câu trả lời trước? Ngoài ra, tôi không nghĩ đoạn thứ hai của bạn là đúng, vì những lý do được nêu trong các câu trả lời khác.
Raphael
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.