Câu trả lời:
Máy ảo là một môi trường điện toán ảo với một tập hợp các hướng dẫn nguyên tử được xác định rõ ràng được hỗ trợ độc lập với bất kỳ ngôn ngữ cụ thể nào và nó thường được coi là một hộp cát cho chính nó. VM tương tự như một tập lệnh của một CPU cụ thể và có xu hướng hoạt động ở mức cơ bản hơn với các khối xây dựng rất cơ bản của các lệnh đó (hoặc mã byte) độc lập với kế tiếp. Một lệnh thực thi chỉ dựa trên trạng thái hiện tại của máy ảo và không phụ thuộc vào thông tin ở nơi khác trong luồng lệnh tại thời điểm đó.
Mặt khác, một trình thông dịch phức tạp hơn ở chỗ nó được thiết kế để phân tích một luồng cú pháp của một ngôn ngữ cụ thể và một ngữ pháp cụ thể phải được giải mã trong ngữ cảnh của các mã thông báo xung quanh. Bạn không thể xem từng byte hoặc thậm chí từng dòng riêng biệt và biết chính xác phải làm gì tiếp theo. Các mã thông báo trong ngôn ngữ không thể được tách biệt giống như chúng có thể liên quan đến các hướng dẫn (mã byte) của VM.
Trình biên dịch Java chuyển đổi ngôn ngữ Java thành luồng mã byte không khác gì trình biên dịch C chuyển đổi các chương trình Ngôn ngữ C thành mã lắp ráp. Mặt khác, một trình thông dịch không thực sự chuyển đổi chương trình thành bất kỳ hình thức trung gian nào được xác định rõ ràng, nó chỉ lấy các hành động của chương trình làm vấn đề của quá trình diễn giải nguồn.
Một thử nghiệm khác về sự khác biệt giữa VM và trình thông dịch là bạn có nghĩ nó độc lập với ngôn ngữ không. Những gì chúng ta biết là Java VM không thực sự cụ thể về Java. Bạn có thể tạo một trình biên dịch từ các ngôn ngữ khác dẫn đến mã byte có thể chạy trên JVM. Mặt khác, tôi không nghĩ rằng chúng ta thực sự sẽ nghĩ đến việc "biên dịch" một số ngôn ngữ khác ngoài Python thành Python để phiên dịch bởi trình thông dịch Python.
Do sự tinh vi của quy trình phiên dịch, đây có thể là một quy trình tương đối chậm .... cụ thể là phân tích và xác định mã thông báo ngôn ngữ, v.v. và hiểu ngữ cảnh của nguồn để có thể thực hiện quy trình thực thi trong trình thông dịch. Để giúp tăng tốc các ngôn ngữ được dịch như vậy, đây là nơi chúng ta có thể xác định các hình thức trung gian của mã nguồn được phân tích trước, mã hóa được mã hóa dễ hiểu hơn. Loại hình nhị phân này vẫn được diễn giải tại thời điểm thực hiện, nó chỉ bắt đầu từ một hình thức ít người đọc hơn để cải thiện hiệu suất. Tuy nhiên, logic thực thi biểu mẫu đó không phải là một máy ảo, bởi vì các mã đó vẫn không thể bị cô lập - bối cảnh của các mã thông báo xung quanh vẫn còn quan trọng, giờ đây chúng ở dạng khác hiệu quả hơn với máy tính.
On the other hand, I don't think we would really think of "compiling" some other language other than Python into Python for interpretation by the Python interpreter.
Có thể viết một ngôn ngữ có thể được biên dịch thành mã byte Python, giống như Scala được biên dịch thành mã byte Java. Trong chế độ tương tác, trình vỏ tương tác của Python biên dịch lệnh đã nhập của bạn thành mã byte và thực thi mã byte đó. Bạn có thể viết shell của riêng mình bằng eval và exec và bạn có thể sử dụng hàm dựng sẵn compile () để biến một chuỗi thành mã byte.
Trong bài đăng này, "máy ảo" đề cập đến xử lý các máy ảo, không phải hệ thống các máy ảo như Qemu hoặc Virtualbox. Một máy ảo quy trình đơn giản là một chương trình cung cấp môi trường lập trình chung - một chương trình có thể được lập trình.
Java có trình thông dịch cũng như máy ảo và Python có máy ảo cũng như trình thông dịch. Lý do "máy ảo" là một thuật ngữ phổ biến hơn trong Java và "trình thông dịch" là một thuật ngữ phổ biến hơn trong Python có liên quan nhiều đến sự khác biệt chính giữa hai ngôn ngữ: gõ tĩnh (Java) so với gõ động (Python). Trong ngữ cảnh này, "loại" đề cập đến các loại dữ liệu nguyên thủy - các loại gợi ý kích thước lưu trữ trong bộ nhớ của dữ liệu. Máy ảo Java có nó dễ dàng. Nó yêu cầu lập trình viên chỉ định kiểu dữ liệu nguyên thủy của từng biến. Điều này cung cấp đủ thông tin cho mã byte Java không chỉ được giải thích và thực thi bởi máy ảo Java, mà thậm chí còn được biên dịch thành các hướng dẫn máy. Máy ảo Python phức tạp hơn theo nghĩa là nó đảm nhận nhiệm vụ bổ sung là tạm dừng trước khi thực hiện từng thao tác để xác định các kiểu dữ liệu nguyên thủy cho từng biến hoặc cấu trúc dữ liệu liên quan đến hoạt động. Python giải phóng lập trình viên khỏi suy nghĩ về các kiểu dữ liệu nguyên thủy và cho phép các hoạt động được thể hiện ở mức cao hơn. Giá của sự tự do này là hiệu suất. "Trình thông dịch" là thuật ngữ ưa thích của Python vì nó phải tạm dừng để kiểm tra các loại dữ liệu và cũng vì cú pháp tương đối ngắn gọn của các ngôn ngữ được gõ động là phù hợp với giao diện tương tác. Không có rào cản kỹ thuật nào trong việc xây dựng giao diện Java tương tác, nhưng cố gắng viết bất kỳ mã được gõ tĩnh nào tương tác sẽ rất tẻ nhạt, vì vậy nó không được thực hiện theo cách đó.
Trong thế giới Java, máy ảo đánh cắp chương trình vì nó chạy các chương trình được viết bằng ngôn ngữ thực sự có thể được biên dịch thành các hướng dẫn máy và kết quả là tốc độ và hiệu quả tài nguyên. Mã byte Java có thể được thực thi bởi máy ảo Java với hiệu năng gần bằng các chương trình được biên dịch, nói một cách tương đối. Điều này là do sự hiện diện của thông tin kiểu dữ liệu nguyên thủy trong mã byte. Máy ảo Java đặt Java vào một danh mục của riêng nó:
xách tay giải thích ngôn ngữ gõ tĩnh
Thứ gần nhất tiếp theo là LLVM, nhưng LLVM hoạt động ở một cấp độ khác:
ngôn ngữ lắp ráp di động
Thuật ngữ "mã byte" được sử dụng trong cả Java và Python, nhưng không phải tất cả mã byte được tạo ra bằng nhau. bytecode chỉ là thuật ngữ chung cho các ngôn ngữ trung gian được sử dụng bởi trình biên dịch / trình thông dịch. Ngay cả các trình biên dịch C như gcc cũng sử dụng ngôn ngữ trung gian (hoặc một số) để hoàn thành công việc. Mã byte Java chứa thông tin về các kiểu dữ liệu nguyên thủy, trong khi mã byte Python thì không. Về mặt này, máy ảo Python (và Bash, Perl, Ruby, v.v.) thực sự chậm hơn về cơ bản so với máy ảo Java, hay nói đúng hơn, đơn giản là nó có nhiều việc phải làm. Rất hữu ích để xem xét thông tin nào được chứa trong các định dạng mã byte khác nhau:
Để vẽ một sự tương tự trong thế giới thực: LLVM hoạt động với các nguyên tử, máy ảo Java hoạt động với các phân tử và Máy ảo Python hoạt động với các vật liệu. Do mọi thứ cuối cùng phải phân hủy thành các hạt hạ nguyên tử (hoạt động của máy thật), máy ảo Python có nhiệm vụ phức tạp nhất.
Trình biên dịch / trình biên dịch của các ngôn ngữ được nhập tĩnh chỉ không có cùng hành lý mà trình thông dịch / trình biên dịch của các ngôn ngữ được gõ động có. Các lập trình viên của các ngôn ngữ gõ tĩnh phải đảm nhận sự chậm chạp, trong đó phần thưởng là hiệu suất. Tuy nhiên, giống như tất cả các chức năng không xác định là bí mật xác định, do đó, tất cả các ngôn ngữ được gõ động đều được nhập tĩnh. Do đó, sự khác biệt về hiệu năng giữa hai họ ngôn ngữ sẽ vượt qua khoảng thời gian Python đổi tên thành HAL 9000.
Các máy ảo của các ngôn ngữ động như Python triển khai một số máy logic lý tưởng hóa và không nhất thiết phải tương ứng rất chặt chẽ với bất kỳ phần cứng vật lý thực tế nào. Ngược lại, máy ảo Java có chức năng tương tự như trình biên dịch C cổ điển, ngoại trừ việc thay vì phát ra các lệnh máy, nó thực hiện các thói quen tích hợp sẵn. Trong Python, một số nguyên là một đối tượng Python có một loạt các thuộc tính và phương thức được đính kèm với nó. Trong Java, một int là một số bit được chỉ định, thường là 32. Nó không thực sự là một so sánh công bằng. Các số nguyên Python thực sự nên được so sánh với lớp Số nguyên Java. Kiểu dữ liệu nguyên thủy "int" của Java không thể so sánh với bất kỳ thứ gì trong ngôn ngữ Python, vì ngôn ngữ Python chỉ đơn giản là thiếu lớp nguyên thủy này và mã byte Python cũng vậy.
Do các biến Java được gõ rõ ràng, nên người ta có thể mong đợi một cách hợp lý một cái gì đó như hiệu suất của Jython sẽ ở trong cùng một sân bóng như cPython . Mặt khác, một máy ảo Java được triển khai bằng Python gần như được đảm bảo là chậm hơn bùn. Và đừng mong đợi Ruby, Perl, v.v., sẽ tốt hơn nữa. Họ không được thiết kế để làm điều đó. Chúng được thiết kế để "viết kịch bản", đó là những gì lập trình bằng ngôn ngữ động được gọi.
Mọi hoạt động diễn ra trong một máy ảo cuối cùng đều phải đạt phần cứng thực sự. Các máy ảo chứa các thường trình được biên dịch sẵn, đủ chung để thực hiện bất kỳ sự kết hợp nào của các hoạt động logic. Một máy ảo có thể không phát ra các hướng dẫn máy mới, nhưng chắc chắn nó đang thực hiện các thói quen của riêng mình lặp đi lặp lại theo trình tự phức tạp. Máy ảo Java, máy ảo Python và tất cả các máy ảo đa năng khác ngoài kia đều có ý nghĩa rằng chúng có thể được áp dụng để thực hiện bất kỳ logic nào bạn có thể mơ, nhưng chúng khác nhau về các nhiệm vụ mà chúng thực hiện đảm nhận, và những nhiệm vụ họ để lại cho lập trình viên.
Psyco cho Python không phải là một máy ảo Python đầy đủ, mà là một trình biên dịch đúng lúc chiếm quyền điều khiển máy ảo Python thông thường tại các điểm mà nó nghĩ rằng nó có thể biên dịch một vài dòng mã - chủ yếu là các vòng lặp mà nó nghĩ là kiểu nguyên thủy của một số biến sẽ không đổi ngay cả khi giá trị thay đổi theo mỗi lần lặp. Trong trường hợp đó, nó có thể từ bỏ một số xác định loại không liên tục của máy ảo thông thường. Tuy nhiên, bạn phải cẩn thận một chút, kẻo bạn sẽ kéo loại ra từ dưới chân Psyco. Tuy nhiên, Pysco thường biết rằng chỉ cần quay lại máy ảo thông thường nếu nó không hoàn toàn tự tin loại sẽ không thay đổi.
Đạo đức của câu chuyện là thông tin kiểu dữ liệu nguyên thủy thực sự hữu ích cho trình biên dịch / máy ảo.
Cuối cùng, để đặt tất cả vào viễn cảnh, hãy xem xét điều này: một chương trình Python được thực thi bởi trình thông dịch / máy ảo Python được triển khai trong Java chạy trên trình thông dịch / máy ảo Java được triển khai trong LLVM chạy trong máy ảo qemu chạy trên iPhone.
trying to write any statically-typed code interactively would be tedious
. Nếu bạn biết OCaml và Haskell, bạn sẽ thấy điều đó không đúng vì chúng là những ngôn ngữ được đánh máy tĩnh rất ngắn gọn.
Có lẽ một lý do cho thuật ngữ khác nhau là người ta thường nghĩ đến việc cung cấp cho trình thông dịch python mã nguồn thô có thể đọc được của con người và không phải lo lắng về mã byte và tất cả điều đó.
Trong Java, bạn phải biên dịch rõ ràng thành mã byte và sau đó chỉ chạy mã byte, không phải mã nguồn trên VM.
Mặc dù Python sử dụng một máy ảo dưới vỏ bọc, từ quan điểm của người dùng, người ta có thể bỏ qua chi tiết này hầu hết thời gian.
Thông dịch viên , dịch mã nguồn thành một số biểu diễn trung gian hiệu quả (mã) và ngay lập tức thực hiện điều này.
Máy ảo , thực thi rõ ràng mã được biên dịch trước được biên dịch được xây dựng bởi trình biên dịch là một phần của hệ thống thông dịch.
Một đặc điểm rất quan trọng của máy ảo là phần mềm chạy bên trong, bị giới hạn ở các tài nguyên do máy ảo cung cấp. Chính xác, nó không thể thoát ra khỏi thế giới ảo của nó. Hãy nghĩ về việc thực thi an toàn mã từ xa, Java Applet.
Trong trường hợp của python, nếu chúng ta giữ các tệp pyc , như được đề cập trong bình luận của bài đăng này, thì cơ chế sẽ trở nên giống như một VM và mã byte này thực thi nhanh hơn - nó vẫn sẽ được hiểu nhưng từ một dạng máy tính thân thiện hơn nhiều . Nếu chúng ta xem xét điều này một cách tổng thể, PVM là bước cuối cùng của Trình thông dịch Python.
Điểm mấu chốt là, khi giới thiệu Trình thông dịch Python, có nghĩa là chúng ta đang đề cập đến nó một cách tổng thể, và khi chúng ta nói PVM, điều đó có nghĩa là chúng ta chỉ nói về một phần của Trình thông dịch Python, môi trường thời gian chạy. Tương tự như Java, chúng tôi đề cập đến các phần khác nhau khác nhau, JRE, JVM, JDK, v.v.
Để biết thêm, Mục nhập Wikipedia: Phiên dịch và Máy ảo . Một cái khác ở đây . Ở đây bạn có thể tìm thấy So sánh các máy ảo ứng dụng . Nó giúp hiểu được sự khác biệt giữa, Trình biên dịch, Phiên dịch và VM.
Thuật ngữ phiên dịch là một thuật ngữ kế thừa có từ các ngôn ngữ kịch bản lệnh shell trước đó. Vì "ngôn ngữ kịch bản" đã phát triển thành các ngôn ngữ đầy đủ tính năng và các nền tảng tương ứng của chúng trở nên tinh vi và hộp cát hơn, sự khác biệt giữa máy ảo và trình thông dịch (theo nghĩa Python), rất nhỏ hoặc không tồn tại.
Trình thông dịch Python vẫn hoạt động giống như một tập lệnh shell, theo nghĩa là nó có thể được thực thi mà không cần một bước biên dịch riêng biệt. Ngoài ra, sự khác biệt giữa trình thông dịch của Python (hoặc Perl hoặc Ruby) và máy ảo của Java chủ yếu là các chi tiết triển khai. (Người ta có thể lập luận rằng Java có hộp cát đầy đủ hơn Python, nhưng cả hai cuối cùng đều cung cấp quyền truy cập vào kiến trúc cơ bản thông qua giao diện C gốc.)
Để cung cấp câu trả lời sâu sắc cho câu hỏi " Tại sao máy ảo Java, nhưng trình thông dịch Python? " Hãy thử quay lại lĩnh vực lý thuyết biên dịch như điểm bắt đầu của cuộc thảo luận.
Quá trình biên dịch chương trình điển hình bao gồm các bước tiếp theo:
a = b + c
là một tuyên bố chính xác từ quan điểm cú pháp, nhưng hoàn toàn không chính xác từ quan điểm ngữ nghĩa nếu a
được khai báo là một đối tượng không đổi)Đồng ý. Bây giờ hãy xác định các điều khoản.
Thông dịch viên , theo nghĩa cổ điển của từ đó, giả định việc thực hiện dựa trên đánh giá chương trình dựa trên AST được sản xuất trực tiếp từ văn bản chương trình . Trong trường hợp đó, một chương trình được phân phối dưới dạng mã nguồn và trình thông dịch được cung cấp bởi văn bản chương trình, thường xuyên theo cách động (tuyên bố theo tuyên bố hoặc từng dòng). Đối với mỗi câu lệnh đầu vào, trình thông dịch xây dựng AST của nó và ngay lập tức đánh giá nó thay đổi "trạng thái" của chương trình. Đây là một hành vi điển hình được thể hiện bằng các ngôn ngữ kịch bản. Hãy xem xét ví dụ Bash, Windows CMD, v.v. Về mặt khái niệm, Python cũng có cách này.
Nếu chúng ta thay thế bước thực hiện dựa trên AST trên thế hệ của bước mã byte nhị phân độc lập với máy trung gian trong trình thông dịch, chúng ta sẽ chia toàn bộ quá trình thực hiện chương trình thành hai giai đoạn riêng biệt: biên dịch và thực thi. Trong trường hợp đó, những gì trước đây là một trình thông dịch sẽ trở thành một trình biên dịch mã byte, nó sẽ chuyển đổi chương trình từ dạng văn bản thành một dạng nhị phân . Sau đó, chương trình được phân phối ở dạng nhị phân đó, nhưng không ở dạng mã nguồn. Trên máy người dùng, mã byte đó được đưa vào một thực thể mới - máy ảo , trên thực tế diễn giải mã byte đó. Do đó, các máy ảo cũng được gọi là trình thông dịch mã byte . Nhưng đặt sự chú ý của bạn ở đây! Một thông dịch viên cổ điển là mộttrình thông dịch văn bản , nhưng một máy ảo là một trình thông dịch nhị phân ! Đây là một cách tiếp cận được thực hiện bởi Java và C #.
Cuối cùng, nếu chúng ta thêm việc tạo mã máy vào trình biên dịch mã byte, chúng ta sẽ đạt được kết quả mà chúng ta gọi là trình biên dịch cổ điển . Một trình biên dịch cổ điển chuyển đổi mã nguồn chương trình thành mã máy của một bộ xử lý cụ thể. Mã máy đó sau đó có thể được thực thi trực tiếp trên bộ xử lý đích mà không cần bất kỳ sự trung gian bổ sung nào (không có bất kỳ loại trình thông dịch nào, cả trình thông dịch văn bản lẫn trình thông dịch nhị phân).
Bây giờ hãy quay lại câu hỏi ban đầu và xem xét Java vs Python.
Java ban đầu được thiết kế để có càng ít phụ thuộc triển khai càng tốt. Thiết kế của nó dựa trên nguyên tắc "viết một lần, chạy mọi nơi" (WORA). Để thực hiện nó, Java được thiết kế ban đầu là một ngôn ngữ lập trình biên dịch vào máy độc lập bytecode nhị phân , mà sau đó có thể được thực hiện trên tất cả các nền tảng có hỗ trợ Java mà không cần biên dịch lại nó. Bạn có thể nghĩ về Java như về C ++ dựa trên WORA . Trên thực tế, Java gần với C ++ hơn là các ngôn ngữ script như Python . Nhưng trái ngược với C ++ , Javađược thiết kế để được biên dịch thành mã byte nhị phân , sau đó được thực thi trong môi trường của máy ảo , trong khi C ++ được thiết kế để được biên dịch theo mã máy và sau đó được bộ xử lý đích thực hiện trực tiếp.
Python ban đầu được thiết kế như một loại ngôn ngữ lập trình kịch bản diễn giải các tập lệnh (các chương trình ở dạng văn bản được viết theo quy tắc ngôn ngữ lập trình). Do đó, Python ban đầu đã hỗ trợ một cách diễn giải động các lệnh hoặc câu lệnh một dòng, như Bash hoặc Windows CMD làm. Vì lý do tương tự, các triển khai ban đầu của Python không có bất kỳ loại trình biên dịch mã byte và máy ảo nào để thực thi mã byte đó bên trong, nhưng ngay từ đầu Python đã yêu cầu trình thông dịch có khả năng hiểu và đánh giá văn bản chương trình Python .
Do đó, về mặt lịch sử, các nhà phát triển Java có xu hướng nói về Máy ảo Java (vì ban đầu, Java là gói trình biên dịch mã byte Java và trình thông dịch mã byte - JVM ) và các nhà phát triển Python có xu hướng nói về trình thông dịch Python (vì ban đầu Python có không phải bất kỳ máy ảo nào và là một loại trình thông dịch văn bản cổ điển thực thi trực tiếp văn bản chương trình mà không có bất kỳ loại biên dịch hoặc chuyển đổi thành bất kỳ dạng mã nhị phân nào).
Hiện tại, Python cũng có máy ảo dưới mui xe và có thể biên dịch và giải thích mã byte của Python. Và thực tế đó làm cho một khoản đầu tư bổ sung vào sự nhầm lẫn " Tại sao máy ảo Java, nhưng trình thông dịch Python?và các chương trình đó sẽ thể hiện chính xác cùng một hành vi và tạo ra cùng một đầu ra từ đầu vào bằng nhau. Sự khác biệt duy nhất có thể quan sát được sẽ là tốc độ thực hiện chương trình và dung lượng bộ nhớ mà trình thông dịch tiêu thụ. Do đó, máy ảo trong Python không phải là một phần không thể tránh khỏi trong thiết kế ngôn ngữ, mà chỉ là một phần mở rộng tùy chọn của trình thông dịch Python chính.
Java có thể được xem xét theo một cách tương tự. Java trong trình duyệt có trình biên dịch JIT và có thể biên dịch có chọn lọc các phương thức của lớp Java thành mã máy của nền tảng đích và sau đó trực tiếp thực hiện nó. Nhưng! Java vẫn sử dụng giải thích mã byte như một cách chính để thực hiện chương trình Java. Giống như các triển khai Python khai thác các máy ảo dưới mui xe chỉ là một kỹ thuật tối ưu hóa, các máy ảo Java sử dụng các trình biên dịch Just-In-Time dành riêng cho mục đích tối ưu hóa. Tương tự, chỉ vì thực tế là việc thực thi trực tiếp mã máy nhanh hơn ít nhất mười lần so với việc giải thích mã byte Java. Và giống như trong trường hợp của Python, sự hiện diện của trình biên dịch JIT dưới vỏ bọc của JVM là hoàn toàn minh bạch cho cả các nhà thiết kế ngôn ngữ Java và các nhà phát triển chương trình Java. Ngôn ngữ lập trình Java tương tự có thể được JVM triển khai có và không có trình biên dịch JIT. Và theo cùng một cách, các chương trình tương tự có thể được thực thi trong các JVM có và không có JIT bên trong, và các chương trình tương tự sẽ thể hiện chính xác cùng một hành vi và tạo ra cùng một đầu ra từ đầu vào bằng nhau trên cả hai JVM (có và không có JIT). Và giống như trong trường hợp của Python, sự khác biệt duy nhất có thể quan sát được giữa chúng, sẽ là về tốc độ thực thi và lượng bộ nhớ mà JVM tiêu thụ. Và cuối cùng, giống như trong trường hợp của Python, JIT trong Java cũng không phải là một phần không thể tránh khỏi trong thiết kế ngôn ngữ, mà chỉ là một phần mở rộng tùy chọn của các triển khai JVM chính. và các chương trình tương tự sẽ thể hiện chính xác cùng một hành vi và tạo ra cùng một đầu ra từ đầu vào bằng nhau trên cả hai JVM (có và không có JIT). Và giống như trong trường hợp của Python, sự khác biệt duy nhất có thể quan sát được giữa chúng, sẽ là về tốc độ thực thi và lượng bộ nhớ mà JVM tiêu thụ. Và cuối cùng, giống như trong trường hợp của Python, JIT trong Java cũng không phải là một phần không thể tránh khỏi trong thiết kế ngôn ngữ, mà chỉ là một phần mở rộng tùy chọn của các triển khai JVM chính. và các chương trình tương tự sẽ thể hiện chính xác cùng một hành vi và tạo ra cùng một đầu ra từ đầu vào bằng nhau trên cả hai JVM (có và không có JIT). Và giống như trong trường hợp của Python, sự khác biệt duy nhất có thể quan sát được giữa chúng, sẽ là về tốc độ thực thi và lượng bộ nhớ mà JVM tiêu thụ. Và cuối cùng, giống như trong trường hợp của Python, JIT trong Java cũng không phải là một phần không thể tránh khỏi trong thiết kế ngôn ngữ, mà chỉ là một phần mở rộng tùy chọn của các triển khai JVM chính.
Từ quan điểm thiết kế và triển khai các máy ảo của Java và Python, chúng khác nhau đáng kể, trong khi (chú ý!) Cả hai vẫn ở lại các máy ảo. JVM là một ví dụ về một máy ảo cấp thấp với các hoạt động cơ bản đơn giản và chi phí gửi lệnh cao. Đến lượt Python là một máy ảo cấp cao, trong đó các hướng dẫn thể hiện hành vi phức tạp và chi phí gửi lệnh không quá đáng kể. Java hoạt động với mức độ trừu tượng rất thấp. JVM hoạt động trên tập hợp nhỏ các kiểu nguyên thủy được xác định rõ và có sự tương ứng rất chặt chẽ (thường là một với một) giữa các hướng dẫn mã byte và hướng dẫn mã máy riêng. Ngược lại, máy ảo Python hoạt động ở mức độ trừu tượng cao, nó hoạt động với các kiểu dữ liệu (đối tượng) phức tạp và hỗ trợ đa hình ad-hoc, trong khi các lệnh bytecode phơi bày hành vi phức tạp, có thể được biểu diễn bằng một loạt các hướng dẫn mã máy riêng. Ví dụ, Python hỗ trợ toán học phạm vi không giới hạn. Do đó, Python VM buộc phải khai thác các số liệu dài cho các số nguyên có khả năng lớn mà kết quả của hoạt động có thể tràn từ máy. Do đó, một lệnh bytecode cho arithologists trong Python có thể hiển thị trong lệnh gọi hàm bên trong Python VM, trong khi trong phép toán số học JVM sẽ hiển thị thành thao tác đơn giản được thể hiện bởi một hoặc một vài lệnh máy gốc. Do đó, Python VM buộc phải khai thác các số liệu dài cho các số nguyên có khả năng lớn mà kết quả của hoạt động có thể tràn từ máy. Do đó, một lệnh bytecode cho arithologists trong Python có thể hiển thị trong lệnh gọi hàm bên trong Python VM, trong khi trong phép toán số học JVM sẽ hiển thị thành thao tác đơn giản được thể hiện bởi một hoặc một vài lệnh máy gốc. Do đó, Python VM buộc phải khai thác các số liệu dài cho các số nguyên có khả năng lớn mà kết quả của hoạt động có thể tràn từ máy. Do đó, một lệnh bytecode cho arithologists trong Python có thể hiển thị trong lệnh gọi hàm bên trong Python VM, trong khi trong phép toán số học JVM sẽ hiển thị thành thao tác đơn giản được thể hiện bởi một hoặc một vài lệnh máy gốc.
Kết quả là, chúng ta có thể rút ra kết luận tiếp theo. Máy ảo Java nhưng trình thông dịch Python là vì:
Do đó, cả Java và Python đều có máy ảo là trình thông dịch mã byte nhị phân, điều này có thể dẫn đến sự nhầm lẫn, chẳng hạn như " Tại sao máy ảo Java, nhưng trình thông dịch Python?"Điểm mấu chốt ở đây là đối với Python, máy ảo không phải là phương tiện chính để thực hiện chương trình, nó chỉ là một phần mở rộng tùy chọn của trình thông dịch văn bản cổ điển. Mặt khác, máy ảo là lõi và không thể tránh khỏi Một phần của hệ sinh thái thực thi chương trình Java. Lựa chọn gõ tĩnh hoặc động cho thiết kế ngôn ngữ lập trình chỉ ảnh hưởng chủ yếu đến mức độ trừu tượng của máy ảo, nhưng không cho biết liệu có cần thiết một máy ảo hay không. , được giải thích hoặc được thực thi trong môi trường của máy ảo, tùy thuộc vào mô hình thực thi mong muốn của chúng.
Không có sự khác biệt thực sự giữa chúng, mọi người chỉ cần tuân theo các quy ước mà người sáng tạo đã chọn.
Đừng quên rằng Python có trình biên dịch JIT có sẵn cho x86, khiến vấn đề càng thêm rối rắm. (Xem psyco).
Việc giải thích chặt chẽ hơn về 'ngôn ngữ được giải thích' chỉ trở nên hữu ích khi thảo luận về các vấn đề về hiệu năng của VM, ví dụ, so với Python, Ruby được coi là chậm hơn vì nó là ngôn ngữ được dịch, không giống như Python - nói cách khác lời nói, bối cảnh là tất cả.
Python có thể giải thích mã mà không cần biên dịch mã thành mã byte. Java không thể .
Python là một ngôn ngữ được giải thích, trái ngược với ngôn ngữ được biên dịch, mặc dù sự khác biệt có thể bị mờ vì sự hiện diện của trình biên dịch mã byte. Điều này có nghĩa là các tệp nguồn có thể được chạy trực tiếp mà không tạo rõ ràng một tệp thực thi được chạy.
(từ tài liệu).
Trong java, mỗi tệp đơn lẻ phải được biên dịch thành một .class
tệp, sau đó chạy trên JVM. Ngược lại, python được nhập bởi tập lệnh chính của bạn, để giúp tăng tốc độ sử dụng tiếp theo của các tệp đó.
Tuy nhiên, trong trường hợp điển hình, hầu hết mã python (ít nhất là CPython) chạy trong một máy stack được mô phỏng, có các hướng dẫn gần như giống hệt với JVM, vì vậy không có sự khác biệt lớn.
Tuy nhiên, lý do thực sự cho sự phân biệt này là bởi vì, ngay từ đầu, java đã tự gắn nhãn là "mã di động, mã thực thi" và python tự coi mình là ngôn ngữ động, được diễn giải bằng REPL. Tên dính!
Trước hết bạn nên hiểu rằng lập trình hay khoa học máy tính nói chung không phải là toán học và chúng tôi không có định nghĩa nghiêm ngặt cho hầu hết các thuật ngữ chúng ta thường sử dụng.
bây giờ cho câu hỏi của bạn:
Thông dịch viên là gì (trong khoa học máy tính)
Nó dịch mã nguồn theo đơn vị thực thi nhỏ nhất và sau đó thực thi đơn vị đó.
máy ảo là gì
trong trường hợp của JVM, máy ảo là một phần mềm chứa Trình thông dịch, trình nạp lớp, trình thu gom rác, bộ lập lịch luồng, trình biên dịch JIT và nhiều thứ khác.
như bạn có thể thấy trình thông dịch là một phần hoặc JVM và toàn bộ JVM không thể được gọi là trình thông dịch vì nó chứa nhiều thành phần khác.
Tại sao lại dùng từ "Phiên dịch" khi nói về python
với java phần biên dịch là rõ ràng. mặt khác, python không rõ ràng như java về quá trình biên dịch và giải thích của nó, từ giải thích phối cảnh của người dùng cuối là cơ chế duy nhất được sử dụng để thực hiện các chương trình python
Không, cả hai đều không giải thích mã byte.
Python chỉ diễn giải mã byte nếu bạn đang chạy với pypy. Mặt khác, nó được biên dịch thành C và được giải thích ở cấp độ đó.
Java biên dịch thành mã byte.
Tôi nghĩ rằng ranh giới giữa cả hai bị mờ đi, mọi người chủ yếu tranh luận về ý nghĩa của từ "thông dịch viên" và mức độ gần gũi của ngôn ngữ đối với mỗi bên của phổ "trình thông dịch ... trình biên dịch". Không ai làm 100% tuy nhiên. Tôi nghĩ thật dễ dàng để viết triển khai Java hoặc Python có giá trị bất kỳ.
Hiện tại cả Java và Python đều có máy ảo và mã byte, mặc dù một máy hoạt động theo kích thước giá trị cụ thể (như số nguyên 32 bit) trong khi các máy khác phải xác định kích thước cho mỗi cuộc gọi, theo tôi không xác định đường viền giữa các thuật ngữ.
Đối số mà Python không xác định chính thức mã byte và nó chỉ tồn tại trong bộ nhớ cũng không thuyết phục được tôi, chỉ vì tôi đang dự định phát triển các thiết bị sẽ chỉ nhận ra mã byte của Python và phần biên dịch sẽ được thực hiện trong máy JS của trình duyệt.
Hiệu suất chỉ là về việc thực hiện cụ thể. Chúng ta không cần phải biết kích thước của đối tượng để có thể làm việc với nó và cuối cùng, trong hầu hết các trường hợp, chúng ta làm việc với các cấu trúc, không phải các loại cơ bản. Có thể tối ưu hóa Python VM theo cách nó sẽ loại bỏ nhu cầu tạo đối tượng mới mỗi lần trong khi tính toán biểu thức, bằng cách sử dụng lại đối tượng hiện có. Một khi nó được thực hiện, không có sự khác biệt hiệu suất toàn cầu giữa việc tính tổng của hai số nguyên, đó là nơi Java tỏa sáng.
Không có sự khác biệt về kẻ giết người giữa hai người, chỉ có một số sắc thái thực hiện và thiếu tối ưu hóa không liên quan đến người dùng cuối, có thể đến lúc cô bắt đầu nhận thấy độ trễ hiệu năng, nhưng một lần nữa, đó là vấn đề triển khai và không phải là kiến trúc.
đối với các bài đăng đề cập rằng python không cần tạo mã byte, tôi không chắc điều đó đúng. Dường như tất cả các hàm gọi trong Python phải có một .__code__.co_code
thuộc tính chứa mã byte. Tôi không thấy một lý do có ý nghĩa để gọi python "không được biên dịch" chỉ vì các tạo phẩm được biên dịch có thể không được lưu; và thường không được lưu bởi thiết kế trong Python, ví dụ như tất cả việc biên dịch mã byte mới cho đầu vào của nó, đây là lý do phạm vi biến hiểu hiểu không nhất quán giữa compile(mode='exec, ...)
và biên dịch, compile(mode='single', ...)
chẳng hạn như giữa chạy tập lệnh python và sử dụng pdb