ดูเหมือนว่าเป็นการยากที่จะอ่าน 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