JVM ป้องกันการเพิ่มประสิทธิภาพการโทรหางหรือไม่


99

ฉันเห็นคำพูดนี้ในคำถาม: ภาษาที่ใช้งานได้ดีในการสร้างบริการเว็บคืออะไร?

โดยเฉพาะอย่างยิ่ง Scala ไม่รองรับการกำจัดหางโทรยกเว้นในฟังก์ชันเรียกซ้ำในตัวเองซึ่ง จำกัด ประเภทขององค์ประกอบที่คุณสามารถทำได้ (นี่เป็นข้อ จำกัด พื้นฐานของ JVM)

นี่คือเรื่องจริง? ถ้าเป็นเช่นนั้น JVM ที่สร้างข้อ จำกัด พื้นฐานนี้คืออะไร?

คำตอบ:


74

โพสต์นี้: การเรียกซ้ำหรือการทำซ้ำ? อาจช่วยได้

ในระยะสั้นการเพิ่มประสิทธิภาพการโทรหางทำได้ยากใน JVM เนื่องจากรูปแบบการรักษาความปลอดภัยและจำเป็นต้องมีการติดตามสแต็กพร้อมใช้งานเสมอ ข้อกำหนดเหล่านี้อาจได้รับการสนับสนุนในทางทฤษฎี แต่อาจต้องใช้รหัสไบต์ใหม่ (ดูข้อเสนออย่างไม่เป็นทางการของ John Rose )

นอกจากนี้ยังมีการสนทนาเพิ่มเติมในSun bug # 4726340ซึ่งการประเมินผล (จากปี 2002) สิ้นสุดลง:

ฉันเชื่อว่าสิ่งนี้สามารถทำได้ แต่ก็ไม่ใช่งานเล็ก ๆ

ปัจจุบันมีการทำงานบางอย่างเกิดขึ้นในดาวินชีเครื่องโครงการ สถานะของโครงการย่อยของ tail call แสดงเป็น "โปรโต 80%"; มันไม่น่าจะทำให้เป็น Java 7 แต่ฉันคิดว่ามันมีโอกาสที่ดีมากที่ Java 8


ฉันไม่ได้ทำตามคำอธิบาย ฉันคิดว่าการเพิ่มประสิทธิภาพการโทรหางถูกนำมาใช้โดยคอมไพเลอร์ สมมติว่าคุณมีฟังก์ชันที่สามารถปรับแต่งการโทรหางโดยคอมไพลเลอร์ได้คุณสามารถมีฟังก์ชันที่ไม่เรียกซ้ำที่เทียบเท่าซึ่งใช้ฟังก์ชันเดียวกันโดยใช้ลูปได้ใช่หรือไม่? ถ้าเป็นเช่นนั้นคอมไพเลอร์ไม่สามารถทำได้ ฉันไม่สามารถติดตามการพึ่งพา JVM ได้ สิ่งนี้เปรียบเทียบกับคอมไพเลอร์ Scheme ที่สร้างโค้ดเนทีฟ i386 อย่างไร
Gautham Ganapathy

4
@Gautham: คำแถลงของฉันเกี่ยวกับการดีบักอ้างอิงถึงการใช้แทรมโพลีนเป็นวิธีแก้ปัญหาสำหรับการขาดการกำจัดการโทรหางบน JVM การกำจัดการโทรหางสามารถทำได้และถูกนำไปใช้ใน JVM (Arnold Schaighofer ทำใน OpenJDK และ LLVM ด้วย) ดังนั้นจึงไม่มีคำถามว่าสามารถทำได้หรือไม่ แน่นอนว่า CLR ของ Microsoft รองรับการกำจัดการโทรหางเป็นเวลา 10 ปีและการเปิดตัว F # ได้แสดงให้เห็นว่ามันเป็นตัวเปลี่ยนเกม ฉันคิดว่าคำตอบคือ JVM หยุดนิ่งมานานแล้ว
JD

3
นี่เป็นความเข้าใจผิดที่พบบ่อยและเป็นข้ออ้างที่เกิดขึ้นบ่อยครั้ง แต่ไม่ถูกต้อง เป็นที่ยอมรับมาหลายปีแล้วว่าการรักษาความปลอดภัยโดยการตรวจสอบสแต็ก (และการจัดเตรียมสแต็กเทรซที่มีประโยชน์) ไม่เข้ากันกับการเรียกหางที่เหมาะสม ตัวอย่างเช่นดูบทความนี้จากปี 2004 citeseerx.ist.psu.edu/viewdoc/…การลงคะแนนเนื่องจากคำตอบไม่ถูกต้อง
Justin Sheehy

5
@JustinSheehy: อะไรไม่ถูกต้อง? คำถามคือ "JVM ป้องกันการเพิ่มประสิทธิภาพการโทรหางหรือไม่" และคำตอบคือ "ไม่ แต่มันยาก"
Michael Myers

5
คุณรู้หรือไม่ว่าใน java8 นี้รวมอยู่ด้วย?
nachokk

27

ข้อ จำกัด พื้นฐานคือ JVM ไม่ได้จัดเตรียมการเรียกหางในรหัสไบต์ดังนั้นจึงไม่มีวิธีโดยตรงสำหรับภาษาที่สร้างขึ้นจาก JVM เพื่อจัดเตรียมการเรียกหางเอง มีวิธีแก้ปัญหาที่สามารถบรรลุเอฟเฟกต์ที่คล้ายกัน (เช่น trampolining) แต่มีต้นทุนต่ำของประสิทธิภาพที่แย่มากและทำให้โค้ดกลางที่สร้างขึ้นทำให้สับสนซึ่งทำให้ดีบักเกอร์ไร้ประโยชน์

ดังนั้น JVM จึงไม่สามารถรองรับภาษาการเขียนโปรแกรมเชิงฟังก์ชันคุณภาพการผลิตใด ๆ ได้จนกว่า Sun จะใช้การเรียกหางใน JVM เอง พวกเขาคุยกันมาหลายปีแล้ว แต่ฉันสงสัยว่าพวกเขาจะใช้การโทรหางมันจะยากมากเพราะพวกเขาได้เพิ่มประสิทธิภาพ VM ก่อนกำหนดก่อนที่จะใช้ฟังก์ชันพื้นฐานดังกล่าวและความพยายามของ Sun มุ่งเน้นไปที่ภาษาแบบไดนามิกมากกว่าภาษาที่ใช้งานได้

ดังนั้นจึงมีข้อโต้แย้งที่ชัดเจนมากว่า Scala ไม่ใช่ภาษาการเขียนโปรแกรมที่ใช้งานได้จริง: ภาษาเหล่านี้ถือว่าการเรียกหางเป็นคุณสมบัติที่สำคัญเนื่องจาก Scheme เปิดตัวครั้งแรกเมื่อ 30 ปีที่แล้ว


5
Hence there is a very strong argument that Scala is not a real functional programming language - การโต้แย้งค่อนข้างอ่อนแอ แน่นอนว่าจะtail calls [as] an essential featureดีถ้าฮาร์ดแวร์พื้นฐาน (หรือเครื่องที่ดี) สนับสนุนโดยตรง แต่เป็นรายละเอียดการใช้งาน
Ingo

8
@Ingo: เฉพาะในกรณีที่คุณไม่ถือว่าสแต็กล้นในโปรแกรมของคุณในขณะรันไทม์ที่ผู้ใช้เห็นว่าเป็นปัญหาสำคัญ ตามตัวติดตามข้อผิดพลาดแม้แต่คอมไพเลอร์ Scala เองก็มีปัญหากับสแต็กล้น ดังนั้นแม้แต่นักพัฒนา Scala ที่เก๋าที่สุดก็ยังเข้าใจผิด ...
JD

7
เป็นผู้สนับสนุนพูด F # แต่ฉันสังเกตคุณมานานแล้ว (แม้กระทั่งหลายปีก่อนใน usenet) เพราะเป็นศัตรูกับทุกสิ่งที่ไม่ใช่ F # แต่การอธิบายรายละเอียดของคุณแสดงให้เห็นว่าคุณไม่รู้ว่าคุณกำลังพูดถึงอะไร เช่นนี้: อาร์กิวเมนต์ของคุณดูเหมือนว่าภาษาที่ฉันสามารถเขียนโปรแกรมที่ยกเลิกด้วย stack overflow ไม่ใช่ภาษาที่ใช้งานได้? แต่ไม่สามารถสร้างอาร์กิวเมนต์เดียวกันสำหรับภาษาที่ฉันสามารถกระตุ้น heap overflow ได้หรือไม่? ดังนั้น F # ศักดิ์สิทธิ์จะไม่นับว่าใช้งานได้
Ingo

7
@Ingo: สำนวนหลายอย่างในการเขียนโปรแกรมเชิงฟังก์ชันเช่นการเรียกซ้ำร่วมกันและรูปแบบการส่งผ่านความต่อเนื่องอาจต้องใช้การกำจัดการโทรหางเพื่อให้ทำงาน หากไม่มีโปรแกรมของคุณจะล้นออกมา หากภาษาไม่สามารถรันโค้ดฟังก์ชันสำนวนได้อย่างน่าเชื่อถือจะใช้งานได้หรือไม่? คำตอบคือการเรียกร้องการตัดสินอย่างที่คุณพูด แต่เป็นความแตกต่างที่สำคัญในทางปฏิบัติ Martin Trojer เพิ่งเผยแพร่บทความในบล็อกที่น่าสนใจเกี่ยวกับเรื่องนี้: martinsprogrammingblog.blogspot.com/2011/11/…
JD

2
ยังคงเป็นเพียงเพราะ JVM (น่าเสียดายที่ไม่มีคำถาม) ไม่สามารถทำการเรียก tail ได้ไม่ได้หมายความว่าการกำจัด tail call เป็นไปไม่ได้ นี่เหมือนกับว่ามีการระบุไว้ว่าการคำนวณจุดลอยตัวสามารถทำได้บนคอมพิวเตอร์ที่มี FPU เท่านั้น
Ingo

22

Scala 2.7.x รองรับการเพิ่มประสิทธิภาพการโทรหางสำหรับการเรียกซ้ำด้วยตนเอง (ฟังก์ชันเรียกตัวเอง) ของวิธีการขั้นสุดท้ายและฟังก์ชันท้องถิ่น

Scala 2.8 อาจมาพร้อมกับการรองรับห้องสมุดสำหรับแทรมโพลีนด้วยเช่นกันซึ่งเป็นเทคนิคในการเพิ่มประสิทธิภาพฟังก์ชันเรียกซ้ำร่วมกัน

การจัดการที่ดีของข้อมูลเกี่ยวกับสถานะของ Scala recursion ที่สามารถพบได้ในบล็อกรวยโดเฮอร์ที


โปรดอัปเดตคำถามเกี่ยวกับสถานะสกาล่าปัจจุบันได้ไหม
om-nom-nom

@ om-nom-nom AFAIK ไม่มีอะไรเปลี่ยนแปลงทั้งฝั่งสกาล่าหรือฝั่ง JVM
Daniel C. Sobral

8

นอกเหนือจากกระดาษที่เชื่อมโยงใน Lambda The Ultimate แล้ว (จากลิงค์ mmyers ที่โพสต์ไว้ด้านบน) John Rose จาก Sun ยังมีอะไรอีกมากมายที่จะพูดเกี่ยวกับการเพิ่มประสิทธิภาพการโทรหาง

http://blogs.oracle.com/jrose/entry/tail_calls_in_the_vm

ฉันได้ยินมาว่ามันอาจจะถูกนำไปใช้กับ JVM ในสักวันหนึ่ง การสนับสนุนการโทรหางเหนือสิ่งอื่นใดกำลังได้รับการพิจารณาบน Da Vinci Machine

http://openjdk.java.net/projects/mlvm/


0

แหล่งที่มาทั้งหมดชี้ให้เห็นว่า JVM ไม่สามารถปรับให้เหมาะสมได้ในกรณีของการเรียกซ้ำหาง แต่เมื่ออ่านการปรับแต่งประสิทธิภาพของ Java (ปี 2003 โอไรลี่) ฉันพบว่าผู้เขียนอ้างว่าเขาสามารถบรรลุประสิทธิภาพการเรียกซ้ำได้มากขึ้นโดยใช้การเรียกซ้ำหาง

คุณสามารถค้นหาคำกล่าวอ้างของเขาได้ที่หน้า 212 (ค้นหา 'tail recursion' ซึ่งควรเป็นผลลัพธ์ที่สอง) สิ่งที่ช่วยให้?


IBM สนับสนุน TCO บางรูปแบบในการนำ JVM ไปใช้งาน (เป็นการเพิ่มประสิทธิภาพจึงไม่รับประกัน) บางทีผู้เขียนการปรับแต่ง Java Performance อาจคิดว่าคุณสมบัตินี้จะถูกนำไปใช้งานโดย JVM ทั้งหมดในที่สุด ibm.com/developerworks/java/library/j-diag8.html
llemieng
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.