ดูเหมือนว่าเป็นการยากที่จะอ่าน Python "virtual machine" ในขณะที่ใน Java "virtual machine" นั้นถูกใช้งานตลอดเวลา
ทั้งตีความรหัสไบต์; ทำไมเรียกหนึ่งเครื่องเสมือนและอื่น ๆ เป็นล่าม
ดูเหมือนว่าเป็นการยากที่จะอ่าน Python "virtual machine" ในขณะที่ใน Java "virtual machine" นั้นถูกใช้งานตลอดเวลา
ทั้งตีความรหัสไบต์; ทำไมเรียกหนึ่งเครื่องเสมือนและอื่น ๆ เป็นล่าม
คำตอบ:
เครื่องเสมือนคือสภาพแวดล้อมการคำนวณเสมือนกับชุดคำสั่งเฉพาะที่กำหนดอย่างดีของอะตอมซึ่งได้รับการสนับสนุนโดยไม่ขึ้นอยู่กับภาษาใด ๆ และเป็นความคิดโดยทั่วไปว่าเป็น sandbox VM นั้นคล้ายคลึงกับชุดคำสั่งของ CPU เฉพาะและมีแนวโน้มที่จะทำงานในระดับพื้นฐานมากขึ้นด้วยโครงสร้างพื้นฐานพื้นฐานของคำสั่งดังกล่าว (หรือรหัสไบต์) ที่เป็นอิสระต่อไป คำสั่งเรียกใช้งานกำหนดขึ้นอยู่กับสถานะปัจจุบันของเครื่องเสมือนเท่านั้นและไม่ขึ้นอยู่กับข้อมูลที่อื่นในสตรีมคำสั่ง ณ เวลานั้น
ล่ามในทางกลับกันมีความซับซ้อนมากกว่าในการที่จะวิเคราะห์กระแสของไวยากรณ์บางอย่างที่เป็นภาษาเฉพาะและของ grammer เฉพาะที่จะต้องถอดรหัสในบริบทของโทเค็นโดยรอบ คุณไม่สามารถดูทีละไบต์หรือแยกแต่ละบรรทัดและรู้ว่าต้องทำอะไรต่อไป ไม่สามารถแยกโทเค็นในภาษาดังกล่าวได้เนื่องจากสามารถสัมพันธ์กับคำแนะนำ (รหัสไบต์) ของ VM
คอมไพเลอร์ Java แปลงภาษา Java เป็นสตรีมโค้ดไบต์ไม่แตกต่างจากคอมไพเลอร์ C แปลงโปรแกรมภาษา C เป็นรหัสแอสเซมบลี ล่ามในทางกลับกันไม่ได้แปลงโปรแกรมเป็นรูปแบบกลางใด ๆ ที่กำหนดไว้อย่างดีมันเพียงใช้การกระทำของโปรแกรมเป็นกระบวนการของการตีความแหล่งที่มา
การทดสอบความแตกต่างอีกอย่างหนึ่งระหว่าง VM และล่ามก็คือคุณคิดว่ามันเป็นภาษาที่เป็นอิสระหรือไม่ สิ่งที่เรารู้ในฐานะ Java VM นั้นไม่ใช่เฉพาะ Java จริงๆ คุณสามารถสร้างคอมไพเลอร์จากภาษาอื่นที่ส่งผลให้รหัสไบต์ที่สามารถทำงานบน JVM ในทางกลับกันฉันไม่คิดว่าเราจะคิดถึง "รวบรวม" ภาษาอื่นนอกเหนือจาก Python เป็น Python สำหรับการตีความโดย Python interpreter
เนื่องจากความซับซ้อนของกระบวนการตีความนี้อาจเป็นกระบวนการที่ค่อนข้างช้า .... โดยเฉพาะการแยกวิเคราะห์และระบุโทเค็นภาษา ฯลฯ และทำความเข้าใจบริบทของแหล่งที่มาเพื่อให้สามารถดำเนินการกระบวนการดำเนินการภายในล่าม เพื่อช่วยเร่งการแปลภาษาที่ตีความเช่นนี้เราสามารถกำหนดรูปแบบกลางของซอร์สโค้ดแบบ pre-parsed, pre-tokenized ที่สามารถตีความได้โดยตรง รูปแบบไบนารีประเภทนี้ยังคงถูกตีความ ณ เวลาดำเนินการมันเพิ่งเริ่มจากรูปแบบที่มนุษย์อ่านได้น้อยกว่ามากเพื่อปรับปรุงประสิทธิภาพ อย่างไรก็ตามตรรกะในการดำเนินการกับรูปแบบนั้นไม่ใช่เครื่องเสมือนเพราะรหัสเหล่านั้นยังไม่สามารถแยกออกได้ - บริบทของโทเค็นรอบข้างยังคงสำคัญ
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.เป็นไปได้ที่จะเขียนภาษาที่สามารถรวบรวมเป็น Python bytecode ได้เช่นเดียวกับ Scala ที่ถูกคอมไพล์เป็น Java bytecode ในโหมดโต้ตอบเชลล์เชิงโต้ตอบของ Python รวบรวมคำสั่งที่คุณพิมพ์ลงใน bytecode แล้วประมวลผล bytecode นั้น คุณสามารถเขียนเชลล์ของคุณเองโดยใช้ eval และ exec และคุณสามารถใช้ฟังก์ชั่นในตัวคอมไพล์ () เพื่อเปลี่ยนสตริงให้เป็น bytecode
ในการโพสต์นี้ "เครื่องเสมือน" หมายถึงการประมวลผลเครื่องเสมือนไม่ใช่ระบบเครื่องเสมือนเช่น Qemu หรือ Virtualbox เครื่องเสมือนกระบวนการเป็นเพียงโปรแกรมที่ให้สภาพแวดล้อมการเขียนโปรแกรมทั่วไป - โปรแกรมที่สามารถตั้งโปรแกรมได้
Java มีล่ามเช่นเดียวกับเครื่องเสมือนและ Python มีเครื่องเสมือนเช่นเดียวกับล่าม เหตุผล "virtual machine" เป็นคำศัพท์ที่พบบ่อยใน Java และ "interpreter" เป็นคำที่พบบ่อยใน Python มีหลายสิ่งที่เกี่ยวข้องกับความแตกต่างที่สำคัญระหว่างสองภาษา: การพิมพ์แบบคงที่ (Java) และการพิมพ์แบบไดนามิก (Python) ในบริบทนี้ "type" หมายถึง ชนิดข้อมูลดั้งเดิม - ชนิดที่แนะนำขนาดการจัดเก็บในหน่วยความจำของข้อมูล เครื่องเสมือน Java นั้นใช้งานง่าย มันต้องการโปรแกรมเมอร์เพื่อระบุชนิดข้อมูลดั้งเดิมของแต่ละตัวแปร สิ่งนี้ให้ข้อมูลที่เพียงพอสำหรับ Java bytecode ไม่เพียง แต่จะถูกตีความและดำเนินการโดยเครื่องเสมือน Java แต่ยังถูกรวบรวมไว้ในคำแนะนำของเครื่อง. เครื่องเสมือน Python มีความซับซ้อนมากขึ้นในแง่ที่ว่าจะใช้ในงานเพิ่มเติมของการหยุดชั่วคราวก่อนที่จะดำเนินการของแต่ละการดำเนินการเพื่อกำหนดชนิดข้อมูลดั้งเดิมสำหรับแต่ละตัวแปรหรือโครงสร้างข้อมูลที่เกี่ยวข้องในการดำเนินการ Python ทำให้โปรแกรมเมอร์ไม่ต้องคิดในแง่ของชนิดข้อมูลดั้งเดิมและช่วยให้การดำเนินการสามารถแสดงในระดับที่สูงขึ้น ราคาของอิสรภาพนี้คือประสิทธิภาพ "Interpreter" เป็นคำที่ต้องการสำหรับ Python เนื่องจากต้องหยุดการตรวจสอบชนิดข้อมูลและเนื่องจากไวยากรณ์ที่กระชับของภาษาที่พิมพ์แบบไดนามิกนั้นค่อนข้างกระชับเหมาะสำหรับอินเตอร์เฟสแบบโต้ตอบ ไม่มีอุปสรรคทางเทคนิคในการสร้างอินเทอร์เฟซ Java แบบโต้ตอบ แต่การพยายามเขียนโค้ดแบบสแตติกใด ๆ แบบโต้ตอบจะน่าเบื่อดังนั้นมันจึงไม่ได้ทำแบบนั้น
ในโลก Java เครื่องเสมือนจะขโมยการแสดงเพราะรันโปรแกรมที่เขียนด้วยภาษาซึ่งสามารถรวบรวมได้จริงในคำสั่งเครื่องและผลลัพธ์คือความเร็วและประสิทธิภาพของทรัพยากร Java bytecode สามารถดำเนินการโดยเครื่องเสมือน Java ที่มีประสิทธิภาพใกล้เคียงกับโปรแกรมที่คอมไพล์ซึ่งค่อนข้างพูด นี่คือสาเหตุที่มีข้อมูลประเภทข้อมูลดั้งเดิมใน bytecode Java virtual machine ทำให้ Java อยู่ในหมวดหมู่ของมันเอง:
พกพาตีความภาษาพิมพ์แบบคงที่
สิ่งที่ใกล้เคียงที่สุดต่อไปคือ LLVM แต่ LLVM ทำงานในระดับที่แตกต่างกัน:
ภาษาแอสเซมบลีตีความแบบพกพา
คำว่า "bytecode" ใช้ทั้งใน Java และ Python แต่ bytecode ทั้งหมดไม่ได้ถูกสร้างขึ้นเท่ากัน bytecode เป็นเพียงคำศัพท์ทั่วไปสำหรับภาษากลางที่ใช้โดยคอมไพเลอร์ / ล่าม แม้แต่คอมไพเลอร์ C เช่น gcc ก็ใช้ภาษาระดับกลาง (หรือหลายภาษา)เพื่อทำงานให้เสร็จ Java bytecode มีข้อมูลเกี่ยวกับชนิดข้อมูลดั้งเดิมในขณะที่ Python bytecode ไม่มี ในแง่นี้เครื่องเสมือน Python (และ Bash, Perl, Ruby และอื่น ๆ ) จะช้ากว่าเครื่องเสมือน Java อย่างแท้จริงหรือมากกว่านั้นมันมีงานต้องทำมากกว่า มันมีประโยชน์ที่จะต้องพิจารณาว่าข้อมูลใดที่อยู่ในรูปแบบ bytecode ที่แตกต่างกัน:
ในการวาดภาพอะนาล็อกในโลกแห่งความจริง: LLVM ทำงานร่วมกับอะตอมเครื่องเสมือน Java ทำงานกับโมเลกุลและเครื่องเสมือน Python ทำงานกับวัสดุ ในที่สุดทุกอย่างต้องย่อยสลายเป็นอนุภาคย่อย (การทำงานของเครื่องจริง) เครื่องเสมือน Python จึงมีงานที่ซับซ้อนที่สุด
ผู้บุกรุก / คอมไพเลอร์ของภาษาที่พิมพ์แบบคงที่เพียงแค่ไม่มีสัมภาระเดียวกับที่ล่าม / ผู้แปลภาษาที่พิมพ์แบบไดนามิกมี โปรแกรมเมอร์ของภาษาที่พิมพ์แบบคงที่จะต้องใช้เวลาหย่อนซึ่งผลตอบแทนคือประสิทธิภาพ อย่างไรก็ตามเช่นเดียวกับทุกฟังก์ชั่น nondeterministic กำหนดอย่างลับ ๆ ดังนั้นทุกภาษาที่พิมพ์แบบไดนามิกแบบไดนามิกแอบพิมพ์แบบคงที่ ความแตกต่างของประสิทธิภาพระหว่างตระกูลภาษาทั้งสองจึงควรปรับระดับในเวลาที่ Python เปลี่ยนชื่อเป็น HAL 9000
เครื่องเสมือนของภาษาแบบไดนามิกเช่น Python ใช้เครื่องโลจิคัลในอุดมคติและไม่จำเป็นต้องสอดคล้องกับฮาร์ดแวร์ทางกายภาพใด ๆ ในทางตรงกันข้าม Java virtual machine นั้นคล้ายกันมากขึ้นในการทำงานกับคอมไพเลอร์ C แบบคลาสสิกยกเว้นว่าแทนที่จะเปล่งคำสั่งเครื่องมันจะเรียกใช้งานรูทีนภายใน ใน Python จำนวนเต็มเป็นออบเจ็กต์ Python ที่มีคุณลักษณะและเมธอดมากมายติดอยู่ ใน Java int มีจำนวนบิตที่กำหนดโดยปกติคือ 32 ไม่ใช่การเปรียบเทียบที่ยุติธรรม Python จำนวนเต็มควรนำมาเปรียบเทียบกับคลาส Java Integer จริงๆ ชนิดข้อมูลดั้งเดิม "int" ของ Java ไม่สามารถเปรียบเทียบกับสิ่งใด ๆ ในภาษา Python ได้เนื่องจากภาษา Python ขาดเลเยอร์ดั้งเดิมเพียงอย่างเดียวและ Python bytecode ก็เช่นกัน
เนื่องจากตัวแปร Java ถูกพิมพ์อย่างชัดเจนเราจึงสามารถคาดหวังได้ว่าบางอย่างเช่นประสิทธิภาพของJythonจะอยู่ใน ballpark เดียวกับ cPython CPythonในทางตรงกันข้าม Java virtual machine ที่ใช้ใน Python นั้นเกือบจะรับประกันว่าจะช้ากว่าโคลน และอย่าคาดหวังว่า Ruby, Perl, และอื่น ๆ พวกเขาไม่ได้ออกแบบมาเพื่อทำเช่นนั้น พวกเขาถูกออกแบบมาสำหรับ "การเขียนสคริปต์" ซึ่งเป็นสิ่งที่เรียกว่าการเขียนโปรแกรมในภาษาแบบไดนามิก
ในที่สุดการดำเนินการทุกอย่างที่เกิดขึ้นในเครื่องเสมือนจะต้องใช้ฮาร์ดแวร์จริง เครื่องเสมือนมีรูทีนที่รวบรวมไว้ล่วงหน้าซึ่งโดยทั่วไปเพียงพอที่จะเรียกใช้งานการดำเนินการทางตรรกะใด ๆ เครื่องเสมือนอาจไม่ได้เปล่งคำสั่งเครื่องใหม่ แต่แน่นอนว่ามันกำลังประมวลผลกิจวัตรของตัวเองซ้ำแล้วซ้ำอีกในลำดับที่ซับซ้อนโดยไม่ตั้งใจ เครื่องเสมือน Java, เครื่องเสมือน Python และเครื่องเสมือนทั่วไปอื่น ๆ ทั้งหมดนั้นมีความเท่าเทียมกันในแง่ที่ว่าพวกเขาสามารถเกลี้ยกล่อมให้ดำเนินการกับตรรกะใด ๆ ที่คุณสามารถฝันได้ แต่แตกต่างกันในแง่ของงานที่พวกเขาทำ รับและสิ่งที่พวกเขาปล่อยให้โปรแกรมเมอร์
Psyco สำหรับ Python ไม่ใช่เครื่องเสมือน Python เต็มรูปแบบ แต่เป็นคอมไพเลอร์ทันเวลาที่จี้เครื่องเสมือน Python ปกติตามที่คิดว่าสามารถรวบรวมรหัสได้สองสามสาย ตัวแปรจะยังคงคงที่แม้ว่าค่าจะเปลี่ยนตามการวนซ้ำแต่ละครั้ง ในกรณีดังกล่าวอาจนำการกำหนดประเภทไม่ต่อเนื่องของเครื่องเสมือนปกติมาใช้ แต่คุณต้องระวังนิดหน่อยไม่ว่าคุณจะดึงมันออกมาจากใต้เท้าของ Psyco อย่างไรก็ตาม Pysco มักจะรู้ที่จะถอยกลับไปที่เครื่องเสมือนปกติหากไม่มั่นใจอย่างสมบูรณ์ประเภทจะไม่เปลี่ยนแปลง
คุณธรรมของเรื่องราวคือข้อมูลประเภทข้อมูลดั้งเดิมนั้นมีประโยชน์ต่อคอมไพเลอร์ / เครื่องเสมือนจริง ๆ
ท้ายที่สุดสิ่งที่ควรพิจารณา: โปรแกรม Python ที่ดำเนินการโดย Python interpreter / virtual machine ที่ใช้ใน Java ที่รันบน Java interpreter / virtual machine ที่ใช้ใน LLVM ที่รันใน qemu virtual machine ที่ทำงานบน iPhone
trying to write any statically-typed code interactively would be tedious. ถ้าคุณรู้ว่า OCaml และ Haskell คุณจะเห็นว่าไม่เป็นความจริงเนื่องจากพวกเขามีมากภาษารัดกุมแบบคงที่พิมพ์
อาจเป็นหนึ่งในเหตุผลสำหรับคำศัพท์ที่แตกต่างกันนั่นก็คือปกติแล้วเราคิดว่าการป้อนล่ามไพ ธ อนดิบที่มนุษย์สามารถอ่านได้และไม่ต้องกังวลกับไบต์และสิ่งต่าง ๆ ทั้งหมด
ใน Java คุณจะต้องคอมไพล์โค้ดไบต์อย่างชัดเจนจากนั้นรันโค้ดไบต์เท่านั้นไม่ใช่ซอร์สโค้ดบน VM
แม้ว่า Python จะใช้เครื่องเสมือนภายใต้ฝาปิด แต่จากมุมมองของผู้ใช้ผู้ใช้สามารถเพิกเฉยต่อรายละเอียดนี้ได้เกือบตลอดเวลา
ล่ามแปลซอร์สโค้ดเป็นการนำเสนอระดับกลางที่มีประสิทธิภาพ (รหัส) และดำเนินการสิ่งนี้ทันที
Virtual Machineเรียกใช้งานโค้ดที่รวบรวมไว้ล่วงหน้าที่สร้างโดยคอมไพเลอร์ซึ่งเป็นส่วนหนึ่งของระบบล่ามอย่างชัดเจน
คุณลักษณะที่สำคัญมากของเครื่องเสมือนคือซอฟต์แวร์ที่ทำงานอยู่ภายในนั้นถูก จำกัด ด้วยทรัพยากรที่ได้รับจากเครื่องเสมือน แม่นยำมันไม่สามารถแยกออกจากโลกเสมือนจริงของมัน คิดว่าการเรียกใช้โค้ดจากระยะไกลอย่างปลอดภัย Java Applets
ในกรณีของงูหลามถ้าเรารักษาpycไฟล์ดังที่ได้กล่าวไว้ในความคิดเห็นของโพสต์นี้กลไกจะกลายเป็นเหมือน VM และ bytecode นี้ทำงานได้เร็วขึ้น - มันจะถูกตีความ แต่จากรูปแบบที่เป็นมิตรกับคอมพิวเตอร์มาก . ถ้าเราดูทั้งหมดนี้ PVM เป็นขั้นตอนสุดท้ายของ Python Interpreter
บรรทัดล่างคือเมื่ออ้างถึง Python Interpreter นั่นหมายความว่าเราอ้างถึงโดยรวมและเมื่อเราพูดว่า PVM นั่นหมายถึงเรากำลังพูดถึงส่วนหนึ่งของ Python Interpreter ซึ่งเป็นสภาวะแวดล้อมรันไทม์ คล้ายกับที่ของ Java เราอ้างอิงส่วนต่าง differentyl, JRE, JVM, JDK ฯลฯ
สำหรับข้อมูลเพิ่มเติมเข้าวิกิพีเดีย: ล่ามและเครื่องเสมือน แต่อีกคนหนึ่งที่นี่ ที่นี่คุณสามารถค้นหาเปรียบเทียบเครื่องเสมือนแอพลิเคชัน ช่วยในการทำความเข้าใจความแตกต่างระหว่าง Compilers, Interpreters และ VMs
ล่ามคำเป็นคำดั้งเดิมย้อนหลังไปถึงภาษาสคริปต์เชลล์ก่อนหน้านี้ ในขณะที่ "ภาษาสคริปต์" ได้พัฒนาเป็นภาษาที่โดดเด่นเต็มรูปแบบและแพลตฟอร์มที่สอดคล้องกันของพวกเขาได้กลายเป็นซับซ้อนและ sandboxed ความแตกต่างระหว่างเครื่องเสมือนและล่าม (ในความหมาย Python) มีขนาดเล็กมากหรือไม่มีอยู่
Python interpreter ยังคงทำงานในลักษณะเดียวกับเชลล์สคริปต์ในแง่ที่ว่ามันสามารถดำเนินการได้โดยไม่มีขั้นตอนการคอมไพล์แยกต่างหาก นอกเหนือจากนั้นความแตกต่างระหว่าง Python interpreter (หรือ Perl หรือ Ruby) และ virtual machine ของ Java นั้นส่วนใหญ่จะมีรายละเอียดการใช้งาน (หนึ่งอาจยืนยันว่า Java เป็น sandboxed อย่างเต็มที่มากกว่า Python แต่ในที่สุดทั้งสองก็ให้การเข้าถึงสถาปัตยกรรมพื้นฐานผ่านอินเตอร์เฟซ C พื้นเมือง)
เพื่อให้คำตอบอย่างลึกซึ้งสำหรับคำถาม " ทำไมต้องใช้ Java Virtual Machine แต่เป็น Python interpreter? " ให้เราลองย้อนกลับไปที่ทฤษฎีการรวบรวมซึ่งเป็นจุดเริ่มต้นของการอภิปราย
กระบวนการทั่วไปของการคอมไพล์โปรแกรมรวมถึงขั้นตอนถัดไป:
a = b + cเป็นคำสั่งที่ถูกต้องจากมุมมองไวยากรณ์ แต่ไม่ถูกต้องสมบูรณ์จากมุมมองเชิงความหมายหากaถูกประกาศเป็นวัตถุคงที่)ตกลง. ตอนนี้ให้กำหนดเงื่อนไข
ล่ามในความหมายของคำว่าคลาสสิกที่จะถือว่าการดำเนินการบนพื้นฐานของการประเมินผลโครงการอยู่บนพื้นฐานของ AST ผลิตได้โดยตรงจากโปรแกรมข้อความ ในกรณีนั้นโปรแกรมจะเผยแพร่ในรูปแบบของซอร์สโค้ดและล่ามจะถูกป้อนด้วยข้อความของโปรแกรมบ่อยครั้งในแบบไดนามิก (คำสั่งต่อคำสั่งหรือคำสั่งต่อบรรทัด) สำหรับแต่ละคำสั่งอินพุตล่ามจะสร้าง AST และประเมินทันทีว่าเปลี่ยน "สถานะ" ของโปรแกรม นี่เป็นพฤติกรรมปกติที่แสดงโดยภาษาสคริปต์ ลองพิจารณาตัวอย่างเช่น Bash, Windows CMD เป็นต้นโดยทั่วไปแล้ว Python ก็ใช้วิธีนี้เช่นกัน
หากเราเปลี่ยนขั้นตอนการดำเนินการตาม AST ในการสร้างขั้นตอนไบนารี bytecode แบบไม่ขึ้นอยู่กับเครื่องจักรในล่ามเราจะแบ่งกระบวนการทั้งหมดของการดำเนินการโปรแกรมออกเป็นสองขั้นตอนแยกจากกัน: การรวบรวมและการดำเนินการ ในกรณีนั้นสิ่งที่เคยเป็นล่ามก่อนหน้านี้จะกลายเป็นคอมไพเลอร์ bytecode ซึ่งจะแปลงโปรแกรมจากรูปแบบของข้อความเป็นรูปแบบไบนารีบางส่วน จากนั้นโปรแกรมจะเผยแพร่ในรูปแบบไบนารีนั้น แต่ไม่ได้อยู่ในรูปของรหัสต้นฉบับ บนเครื่องของผู้ใช้ไบต์นั้นจะถูกป้อนเข้าสู่เอนทิตีใหม่ - เครื่องเสมือนซึ่งในความเป็นจริงตีความว่า bytecode ด้วยเหตุนี้เครื่องเสมือนจึงถูกเรียกว่าbytecode interpreter ล่าม แต่ใส่ความสนใจของคุณที่นี่! ล่ามคลาสสิคคือtext interpreterแต่เครื่องเสมือนเป็นแปลไบนารี ! นี่เป็นวิธีการที่ดำเนินการโดย Java และ C #
สุดท้ายถ้าเราเพิ่มการสร้างรหัสเครื่องที่จะเรียบเรียง bytecode ที่เราประสบความสำเร็จในผลสิ่งที่เราเรียกคลาสสิกคอมไพเลอร์ คอมไพเลอร์แบบดั้งเดิมจะแปลงซอร์สโค้ดโปรแกรมเป็นโค้ดเครื่องของโปรเซสเซอร์เฉพาะ รหัสเครื่องนั้นสามารถดำเนินการโดยตรงบนตัวประมวลผลเป้าหมายโดยไม่ต้องทำการไกล่เกลี่ยเพิ่มเติมใด ๆ (โดยไม่ต้องใช้ตัวแปลใด ๆ
ตอนนี้ให้กลับไปที่คำถามเดิมและพิจารณา Java vs Python
Javaได้รับการออกแบบเริ่มแรกให้มีการพึ่งพาการใช้งานน้อยที่สุด การออกแบบขึ้นอยู่กับหลักการ "เขียนครั้งเดียวทำงานได้ทุกที่" (WORA) เพื่อนำไปใช้งานในตอนแรกJavaได้รับการออกแบบให้เป็นภาษาการเขียนโปรแกรมที่รวบรวมเป็นไบเทคโค้ดโดยไม่ต้องพึ่งพาเครื่องซึ่งสามารถประมวลผลได้บนทุกแพลตฟอร์มที่รองรับJavaโดยไม่จำเป็นต้องคอมไพล์ซ้ำ คุณสามารถคิดเกี่ยวกับJavaชอบเกี่ยวกับวรตามC ++ ที่จริงJavaอยู่ใกล้กับC ++กว่าภาษาสคริปต์เช่นงูหลาม แต่ตรงกันข้ามกับC ++ , Javaถูกออกแบบมาเพื่อรวบรวมเป็นไบเทคไบต์ซึ่งจะถูกดำเนินการในสภาพแวดล้อมของเครื่องเสมือนในขณะที่C ++ถูกออกแบบมาเพื่อรวบรวมในรหัสเครื่องแล้วดำเนินการโดยตรงโดยหน่วยประมวลผลเป้าหมาย
Pythonได้รับการออกแบบในขั้นต้นเป็นภาษาการเขียนโปรแกรมชนิดหนึ่งซึ่งตีความสคริปต์ (โปรแกรมในรูปแบบของข้อความที่เขียนตามกฎการเขียนโปรแกรมภาษา) ด้วยเหตุนี้ Python จึงสนับสนุนการตีความคำสั่งหรือข้อความสั่งแบบบรรทัดเดียวแบบไดนามิกเช่น Bash หรือ Windows CMD ด้วยเหตุผลเดียวกันการใช้งานเริ่มต้นของ Python ไม่มีคอมไพเลอร์ bytecode และเครื่องเสมือนใด ๆ สำหรับการดำเนินการของ bytecode ภายใน แต่ตั้งแต่เริ่มต้นPythonจำเป็นต้องใช้ล่ามซึ่งสามารถเข้าใจและประเมินข้อความโปรแกรม Python ได้
เนื่องจากนี้ในอดีตJavaนักพัฒนามีแนวโน้มที่จะพูดคุยเกี่ยวกับโปรแกรม Java Virtual Machine (เพราะตอนแรกJavaได้มาเป็นแพคเกจของJavaคอมไพเลอร์ bytecode และbytecode ล่าม - JVM ) และงูหลามนักพัฒนามีแนวโน้มที่จะพูดคุยเกี่ยวกับงูหลามล่าม (เพราะตอนแรกงูใหญ่มี ไม่ใช่เครื่องเสมือนและเป็นล่ามข้อความคลาสสิคที่รันข้อความโปรแกรมโดยตรงโดยไม่มีการคอมไพล์หรือแปลงในรูปแบบของรหัสไบนารี่ใด ๆ )
ปัจจุบันไพ ธ อนยังมีเครื่องเสมือนภายใต้ประทุนและสามารถรวบรวมและตีความ Python bytecode และความจริงนั้นทำให้การลงทุนเพิ่มเติมในความสับสน " ทำไม Java Virtual Machine แต่เป็น Python interpreter?และโปรแกรมนั้นจะแสดงให้เห็นถึงพฤติกรรมที่เหมือนกันและสร้างผลลัพธ์เดียวกันจากอินพุตที่เท่ากัน ความแตกต่างที่สังเกตได้เท่านั้นคือความเร็วของการเรียกใช้โปรแกรมและปริมาณหน่วยความจำที่ล่ามใช้ ดังนั้นเครื่องเสมือนใน Python จึงไม่ใช่ส่วนที่หลีกเลี่ยงไม่ได้ในการออกแบบภาษา แต่เป็นเพียงส่วนเสริมเสริมของ Python interpreter
Java สามารถพิจารณาในลักษณะที่คล้ายกัน Java ภายใต้ประทุนมีคอมไพเลอร์ JIT และสามารถรวบรวมวิธีการของคลาส Java เป็นรหัสเครื่องของแพลตฟอร์มเป้าหมายแล้วดำเนินการโดยตรง แต่! Java ยังคงใช้การตีความ bytecode เป็นวิธีหลักของการเรียกใช้โปรแกรม Java เช่นเดียวกับการใช้งาน Python ซึ่งใช้ประโยชน์จากเครื่องเสมือนภายใต้ประทุนเป็นเทคนิคการปรับให้เหมาะสมที่สุดเครื่องเสมือน Java ใช้ Just-In-Time compilers เพื่อการปรับให้เหมาะสมโดยเฉพาะ ในทำนองเดียวกันเพียงเพราะการดำเนินการโดยตรงของรหัสเครื่องอย่างน้อยสิบครั้งเร็วกว่าการตีความของ Java bytecode และเช่นเดียวกับในกรณีของ Python การมี JIT compiler ภายใต้ประทุนของ JVM นั้นโปร่งใสสำหรับนักออกแบบภาษา Java และนักพัฒนาโปรแกรม Java อย่างแน่นอน ภาษาโปรแกรม Java เดียวกันสามารถนำไปใช้โดย JVM โดยมีและไม่มีคอมไพเลอร์ JIT และในทำนองเดียวกันโปรแกรมเดียวกันสามารถดำเนินการใน JVM โดยมีและไม่มี JIT อยู่ภายในและโปรแกรมเดียวกันจะแสดงให้เห็นถึงพฤติกรรมเดียวกันและสร้างผลลัพธ์เดียวกันจากอินพุตที่เท่ากันบน JVM ทั้งที่มีและไม่มี JIT และเช่นเดียวกับในกรณีของ Python ความแตกต่างที่สังเกตได้เพียงอย่างเดียวคือความเร็วในการประมวลผลและปริมาณหน่วยความจำที่ใช้โดย JVM และในที่สุดเช่นในกรณีของ Python JIT ใน Java ก็ไม่ได้เป็นส่วนหนึ่งของการออกแบบภาษาอย่างหลีกเลี่ยงไม่ได้ แต่เป็นเพียงส่วนเสริมของการใช้งาน JVM ที่สำคัญ และโปรแกรมเดียวกันจะแสดงให้เห็นถึงพฤติกรรมที่เหมือนกันและสร้างผลลัพธ์เดียวกันจากอินพุตที่เท่ากันบน JVM ทั้งสอง (โดยมีและไม่มี JIT) และเช่นเดียวกับในกรณีของ Python ความแตกต่างที่สังเกตได้เพียงอย่างเดียวคือความเร็วในการประมวลผลและปริมาณหน่วยความจำที่ใช้โดย JVM และในที่สุดเช่นในกรณีของ Python JIT ใน Java ก็ไม่ได้เป็นส่วนหนึ่งของการออกแบบภาษาอย่างหลีกเลี่ยงไม่ได้ แต่เป็นเพียงส่วนเสริมของการใช้งาน JVM ที่สำคัญ และโปรแกรมเดียวกันจะแสดงให้เห็นถึงพฤติกรรมที่เหมือนกันและสร้างผลลัพธ์เดียวกันจากอินพุตที่เท่ากันบน JVM ทั้งสอง (โดยมีและไม่มี JIT) และเช่นเดียวกับในกรณีของ Python ความแตกต่างที่สังเกตได้เพียงอย่างเดียวคือความเร็วในการประมวลผลและปริมาณหน่วยความจำที่ใช้โดย JVM และในที่สุดเช่นในกรณีของ Python JIT ใน Java ก็ไม่ได้เป็นส่วนหนึ่งของการออกแบบภาษาอย่างหลีกเลี่ยงไม่ได้ แต่เป็นเพียงส่วนเสริมของการใช้งาน JVM ที่สำคัญ
จากมุมมองของการออกแบบและการใช้งานเครื่องเสมือนของ Java และ Python พวกเขาแตกต่างกันอย่างมีนัยสำคัญในขณะที่ (ความสนใจ!) ทั้งสองยังคงอยู่เครื่องเสมือน JVM เป็นตัวอย่างของเครื่องเสมือนระดับต่ำที่มีการใช้งานพื้นฐานอย่างง่ายและค่าใช้จ่ายในการส่งคำสั่งสูง หลามในตอนนั้นเป็นเครื่องเสมือนระดับสูงซึ่งคำสั่งแสดงให้เห็นถึงพฤติกรรมที่ซับซ้อนและค่าใช้จ่ายในการจัดส่งคำสั่งไม่สำคัญนัก Java ทำงานด้วยระดับนามธรรมที่ต่ำมาก JVM ทำงานกับชุดประเภทดั้งเดิมขนาดเล็กที่กำหนดไว้อย่างดีและมีการติดต่อที่แน่นมาก ในทางกลับกันเครื่องเสมือน Python ทำงานที่ระดับนามธรรมสูงมันทำงานกับชนิดข้อมูลที่ซับซ้อน (วัตถุ) และสนับสนุน ad-hoc polymorphism ในขณะที่คำสั่ง bytecode เปิดเผยพฤติกรรมที่ซับซ้อนซึ่งสามารถแสดงด้วยชุดคำสั่งรหัสเครื่องหลายแบบ ตัวอย่างเช่น Python สนับสนุนคณิตศาสตร์ในขอบเขตที่ไม่ จำกัด ดังนั้น Python VM ถูกบังคับให้ใช้ประโยชน์จาก arithmetics ยาวสำหรับจำนวนเต็มขนาดใหญ่ที่อาจเป็นผลของการดำเนินการสามารถล้นคำเครื่อง ดังนั้นคำสั่ง bytecode หนึ่งคำสำหรับ arithmetics ใน Python สามารถเปิดเผยในการเรียกใช้ฟังก์ชั่นภายใน Python VM ในขณะที่การดำเนินการทางคณิตศาสตร์ JVM จะเปิดเผยในการดำเนินการอย่างง่ายที่แสดงโดยคำสั่งเครื่องพื้นเมืองหนึ่งหรือสองสามตัว ดังนั้น Python VM ถูกบังคับให้ใช้ประโยชน์จาก arithmetics ยาวสำหรับจำนวนเต็มขนาดใหญ่ที่อาจเป็นผลของการดำเนินการสามารถล้นคำเครื่อง ดังนั้นคำสั่ง bytecode หนึ่งคำสำหรับ arithmetics ใน Python สามารถเปิดเผยในการเรียกใช้ฟังก์ชั่นภายใน Python VM ในขณะที่การดำเนินการทางคณิตศาสตร์ JVM จะเปิดเผยในการดำเนินการอย่างง่ายที่แสดงโดยคำสั่งเครื่องพื้นเมืองหนึ่งหรือสองสามตัว ดังนั้น Python VM ถูกบังคับให้ใช้ประโยชน์จาก arithmetics ยาวสำหรับจำนวนเต็มขนาดใหญ่ที่อาจเป็นผลของการดำเนินการสามารถล้นคำเครื่อง ดังนั้นคำสั่ง bytecode หนึ่งคำสำหรับ arithmetics ใน Python สามารถเปิดเผยในการเรียกใช้ฟังก์ชั่นภายใน Python VM ในขณะที่การดำเนินการทางคณิตศาสตร์ JVM จะเปิดเผยในการดำเนินการอย่างง่ายที่แสดงโดยคำสั่งเครื่องพื้นเมืองหนึ่งหรือสองสามตัว
เป็นผลให้เราสามารถสรุปข้อสรุปต่อไป Java Virtual Machine แต่ตัวแปล Python เป็นเพราะ:
ดังนั้นทั้ง Java และ Python มีเครื่องเสมือนเป็นตัวแปลไบนารี bytecode ซึ่งสามารถนำไปสู่ความสับสนเช่น " Why Java Virtual Machine แต่เป็น Python interpreter? " จุดสำคัญที่นี่คือสำหรับ Python เครื่องเสมือนไม่ใช่วิธีหลักหรือจำเป็นสำหรับการดำเนินการของโปรแกรม มันเป็นเพียงส่วนเสริมเสริมของล่ามข้อความคลาสสิก ในอีกทางหนึ่งเครื่องเสมือนเป็นแกนหลักและเป็นส่วนที่หลีกเลี่ยงไม่ได้ของระบบนิเวศในการทำงานของโปรแกรม Java ตัวเลือกการพิมพ์แบบคงที่หรือแบบไดนามิกสำหรับการออกแบบภาษาการเขียนโปรแกรมส่งผลกระทบส่วนใหญ่เป็นระดับนามธรรมของเครื่องเสมือนเท่านั้น แต่ไม่ได้กำหนดว่าต้องใช้เครื่องเสมือนหรือไม่ ภาษาที่ใช้ระบบการพิมพ์ทั้งสองสามารถออกแบบให้คอมไพล์ตีความหรือดำเนินการภายในสภาพแวดล้อมของเครื่องเสมือนทั้งนี้ขึ้นอยู่กับรูปแบบการดำเนินการที่ต้องการ
ไม่มีความแตกต่างที่แท้จริงระหว่างพวกเขาผู้คนเพียงทำตามแบบแผนที่ผู้สร้างเลือกไว้
อย่าลืมว่า Python มีคอมไพเลอร์ JIT สำหรับ x86 ทำให้เกิดความสับสนมากขึ้น (ดู psyco)
การตีความที่เข้มงวดมากขึ้นของ 'ภาษาที่ถูกตีความ' จะมีประโยชน์เฉพาะเมื่อพูดถึงปัญหาด้านประสิทธิภาพของ VM ตัวอย่างเช่นเมื่อเปรียบเทียบกับ Python นั้น Ruby ถูกพิจารณาว่าช้ากว่าเพราะเป็นภาษาที่ตีความแล้วไม่เหมือนกับ Python คำบริบทคือทุกอย่าง
Python สามารถตีความรหัสได้โดยไม่ต้องคอมไพล์โค้ดดังกล่าวเป็น bytecode Java ไม่สามารถ
Python เป็นภาษาที่ถูกตีความเมื่อเทียบกับภาษาที่รวบรวมแม้ว่าความแตกต่างสามารถเลือนลางเนื่องจากการมีอยู่ของคอมไพเลอร์ bytecode ซึ่งหมายความว่าไฟล์ต้นฉบับสามารถรันได้โดยตรงโดยไม่ต้องสร้างไฟล์ที่รันได้อย่างชัดเจน
(จากเอกสาร)
ใน java ทุกไฟล์จะต้องรวบรวมเป็น.classไฟล์ซึ่งจะทำงานบน JVM ในทางกลับกันไพ ธ อนนำเข้าโดยสคริปต์หลักของคุณเพื่อช่วยเร่งการใช้ไฟล์เหล่านั้นในภายหลัง
อย่างไรก็ตามในกรณีทั่วไปรหัสไพ ธ อนส่วนใหญ่ (อย่างน้อย CPython) ทำงานในเครื่องจำลองแบบสแต็กซึ่งมีคำแนะนำที่เหมือนกันเกือบทั้งหมดกับ JVM ดังนั้นจึงไม่มีความแตกต่างกัน
อย่างไรก็ตามเหตุผลที่แท้จริงของความแตกต่างคือเนื่องจากจาวาได้สร้างตราสินค้าของตัวเองว่าเป็น "bytecode แบบพกพาที่ปฏิบัติการได้" และไพ ธ อนทำเครื่องหมายว่าเป็นภาษาไดนามิกแปลภาษาด้วย REPL ชื่อติด!
ก่อนอื่นคุณควรเข้าใจว่าการเขียนโปรแกรมหรือวิทยาศาสตร์คอมพิวเตอร์โดยทั่วไปไม่ใช่คณิตศาสตร์และเราไม่มีคำจำกัดความที่เข้มงวดสำหรับคำศัพท์ส่วนใหญ่ที่เราใช้บ่อย
ตอนนี้คำถามของคุณ:
ล่ามคืออะไร (ในสาขาวิทยาศาสตร์คอมพิวเตอร์)
มันแปลซอร์สโค้ดด้วยหน่วยปฏิบัติการที่เล็กที่สุดจากนั้นเรียกใช้งานหน่วยนั้น
เครื่องเสมือนคืออะไร
ในกรณีของ JVM เครื่องเสมือนเป็นซอฟต์แวร์ที่มีตัวแปล, ตัวโหลดคลาส, ตัวรวบรวมขยะ, ตัวกำหนดเวลาเธรด, ตัวแปล JIT และสิ่งอื่น ๆ อีกมากมาย
ในขณะที่คุณเห็นล่ามเป็นส่วนหนึ่งหรือ JVM และ JVM ทั้งหมดไม่สามารถเรียกว่าล่ามเพราะมันมีส่วนประกอบอื่น ๆ
เหตุใดจึงใช้คำว่า "ล่าม" เมื่อพูดถึงงูหลาม
ด้วย java ส่วนการรวบรวมนั้นชัดเจน งูหลามในทางกลับกันไม่ชัดเจนว่าเป็นจาวาเกี่ยวกับการรวบรวมและการตีความของมันจากการตีความมุมมองของผู้ใช้เป็นกลไกเดียวที่ใช้ในการรันโปรแกรมหลาม
ไม่พวกเขาทั้งสองไม่ตีความรหัสไบต์
Python ตีความเฉพาะ bytecode หากคุณใช้งานกับ pypy มิฉะนั้นจะรวบรวมเป็น C และตีความในระดับนั้น
Java คอมไพล์ไปยัง bytecode
ฉันคิดว่าเส้นแบ่งระหว่างทั้งสองเบลอคนส่วนใหญ่โต้เถียงความหมายของคำว่า "ล่าม" และความใกล้ชิดของภาษานั้นอยู่ที่แต่ละด้านของสเปกตรัม "ล่ามแปล ... คอมไพเลอร์" ไม่มีใครทำ 100% อย่างไรก็ตาม ฉันคิดว่ามันง่ายที่จะเขียนการใช้งาน Java หรือ Python ซึ่งมีค่าใด ๆ ของสเปกตรัม
ขณะนี้ทั้ง Java และ Python มีเครื่องเสมือนและ bytecode แม้ว่าหนึ่งดำเนินการโดยขนาดค่าคอนกรีต (เช่นจำนวนเต็ม 32 บิต) ในขณะที่อื่น ๆ มีการกำหนดขนาดสำหรับการโทรแต่ละครั้งซึ่งในความคิดของฉันไม่ได้กำหนดชายแดนระหว่างเงื่อนไข
อาร์กิวเมนต์ที่ Python ไม่ได้กำหนดไว้อย่างเป็นทางการโดยรหัสและมีอยู่ในหน่วยความจำเท่านั้นยังไม่เชื่อฉันเพียงเพราะฉันวางแผนที่จะพัฒนาอุปกรณ์ที่จะรับรู้เพียง Python bytecode และส่วนการรวบรวมจะทำในเครื่อง JS เบราว์เซอร์
ประสิทธิภาพเป็นเพียงการดำเนินการอย่างเป็นรูปธรรม เราไม่จำเป็นต้องรู้ขนาดของวัตถุเพื่อให้สามารถทำงานกับมันและในที่สุดกรณีส่วนใหญ่เราทำงานกับโครงสร้างไม่ใช่ประเภทพื้นฐาน เป็นไปได้ที่จะเพิ่มประสิทธิภาพ Python VM ในวิธีที่จะขจัดความต้องการในการสร้างวัตถุใหม่ในแต่ละครั้งในระหว่างการคำนวณนิพจน์โดยการนำวัตถุที่มีอยู่แล้วกลับมาใช้ใหม่ เมื่อดำเนินการเสร็จแล้วจะไม่มีความแตกต่างด้านประสิทธิภาพการทำงานระดับโลกระหว่างการคำนวณผลรวมของจำนวนเต็มสองจำนวนซึ่งเป็นที่ที่ Java ส่องสว่าง
ไม่มีความแตกต่างระหว่างนักฆ่ามีเพียงความแตกต่างของการใช้งานบางอย่างและการปรับให้เหมาะสมซึ่งไม่เกี่ยวข้องกับผู้ใช้อาจจะถึงจุดที่เธอเริ่มสังเกตเห็นความล่าช้าของประสิทธิภาพ แต่อีกครั้งเป็นการใช้งานและไม่ใช่ปัญหาสถาปัตยกรรม
สำหรับโพสต์ที่พูดถึงว่าหลามไม่จำเป็นต้องสร้างรหัสไบต์ฉันไม่แน่ใจว่ามันเป็นเรื่องจริง ดูเหมือนว่า callables ทั้งหมดใน Python จะต้องมี.__code__.co_codeคุณลักษณะที่มีรหัสไบต์ ฉันไม่เห็นเหตุผลที่มีความหมายในการเรียก python "ไม่ได้รวบรวม" เพียงเพราะสิ่งที่รวบรวมอาจไม่ถูกบันทึก; และบ่อยครั้งที่ไม่ได้รับการบันทึกโดยการออกแบบใน Python ตัวอย่างเช่น comprehension compileension bytecode ใหม่สำหรับ input มันนี่คือเหตุผลที่ขอบเขตของตัวแปร comprehension ไม่สอดคล้องกันcompile(mode='exec, ...)และระหว่างการคอมไพล์compile(mode='single', ...)เช่นระหว่างการเรียกใช้สคริปต์ python และการใช้ pdb