ภาษาไดนามิกเช่น Ruby / Python สามารถเข้าถึง C / C ++ เหมือนประสิทธิภาพได้หรือไม่?


64

ฉันสงสัยว่าเป็นไปได้ไหมที่จะสร้างคอมไพเลอร์สำหรับภาษาไดนามิกเช่น Ruby เพื่อให้มีประสิทธิภาพที่คล้ายกันและเทียบเท่ากับ C / C ++? จากสิ่งที่ฉันเข้าใจเกี่ยวกับคอมไพเลอร์ใช้ Ruby เช่นการคอมไพล์โค้ด Ruby นั้นไม่สามารถมีประสิทธิภาพได้เพราะวิธีที่ Ruby จัดการกับการสะท้อนคุณสมบัติต่าง ๆ เช่นการแปลงชนิดอัตโนมัติจากจำนวนเต็มเป็นจำนวนเต็มใหญ่และการขาดการพิมพ์แบบคงที่ สำหรับทับทิมยากมาก

เป็นไปได้ไหมที่จะสร้างคอมไพเลอร์ที่สามารถรวบรวม Ruby หรือภาษาไดนามิกอื่น ๆ ไปยังไบนารีที่ทำงานใกล้ชิดกับ C / C ++ มากขึ้น? มีเหตุผลพื้นฐานที่ทำให้คอมไพเลอร์ JIT เช่น PyPy / Rubinius ในที่สุดจะหรือไม่จะไม่ตรงกับ C / C ++ ในการทำงาน?

หมายเหตุ: ฉันเข้าใจว่า "ประสิทธิภาพ" อาจคลุมเครือดังนั้นเพื่อล้างสิ่งนั้นฉันหมายความว่าถ้าคุณสามารถทำ X ใน C / C ++ ด้วยประสิทธิภาพ Y คุณสามารถทำ X ใน Ruby / Python ที่มีประสิทธิภาพใกล้เคียงกับ Y ได้หรือไม่ โดยที่ X คือทุกอย่างตั้งแต่ไดรเวอร์อุปกรณ์และรหัส OS ไปจนถึงเว็บแอปพลิเคชัน


1
คุณสามารถเรียบเรียงคำถามใหม่อีกครั้งเพื่อกระตุ้นให้เกิดคำตอบที่ได้รับการสนับสนุนจากหลักฐานที่เหมาะสมมากกว่าคนอื่น ๆ หรือไม่?
Raphael

@ ราฟาเอลฉันได้ไปข้างหน้าและแก้ไข ฉันคิดว่าการแก้ไขของฉันไม่ได้เปลี่ยนความหมายของคำถาม แต่ทำให้การเชิญความคิดเห็นน้อยลง
Gilles

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

คำถามนี้เป็นผู้เริ่มต้นของสงครามศาสนา และอย่างที่เราเห็นได้จากคำตอบเรามีอยู่แม้ว่าจะเป็นอารยธรรม
Andrej Bauer

มีภาษาแบบไดนามิกที่อนุญาตให้ใช้คำอธิบายประกอบประเภทที่เป็นตัวเลือก (เช่น: Clojure) จากสิ่งที่ฉันรู้ประสิทธิภาพการทำงานที่เกี่ยวข้องกับฟังก์ชั่นคำอธิบายประกอบประเภทเทียบเท่ากับเมื่อภาษาจะพิมพ์แบบคงที่
Pedro Morte Rolo

คำตอบ:


68

ทุกคนที่กล่าวว่า“ใช่” ฉันจะมีเคาน์เตอร์จุดว่าคำตอบคือ“ไม่” โดยการออกแบบ ภาษาเหล่านั้นจะไม่สามารถจับคู่กับประสิทธิภาพของภาษาที่รวบรวมแบบคงที่ได้

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

อย่างไรก็ตามมีอีกด้านหนึ่งของเหรียญ: ข้อมูลเพิ่มเติมนี้จำเป็นต้องได้รับการติดตาม สำหรับสถาปัตยกรรมสมัยใหม่นี่คือนักฆ่าประสิทธิภาพ

วิลเลี่ยมเอ็ดเวิร์ดส์มีภาพรวมที่ดีของการโต้แย้ง

โดยเฉพาะอย่างยิ่งการเพิ่มประสิทธิภาพที่กล่าวถึงโดย Kos ไม่สามารถใช้เกินขอบเขตที่ จำกัด มากเว้นแต่ว่าคุณจะ จำกัด พลังการแสดงออกของภาษาของคุณค่อนข้างรุนแรงตามที่ Devin กล่าวไว้ แน่นอนว่านี่เป็นการแลกเปลี่ยนที่มีประโยชน์ แต่เพื่อประโยชน์ในการอภิปรายคุณจะต้องจบด้วยภาษาแบบคงที่ไม่ใช่แบบไดนามิก ภาษาเหล่านั้นแตกต่างจาก Python หรือ Ruby โดยที่คนส่วนใหญ่เข้าใจ

William อ้างอิงสไลด์ IBM ที่น่าสนใจ:

  • ตัวแปรทุกตัวสามารถพิมพ์ได้แบบไดนามิก: ต้องการการตรวจสอบประเภท
  • ทุกคำสั่งอาจมีข้อยกเว้นเนื่องจากประเภทไม่ตรงกันและอื่น ๆ : ต้องการการตรวจสอบข้อยกเว้น
  • สามารถเพิ่มลบและเปลี่ยนแปลงทุกฟิลด์และสัญลักษณ์ได้ในขณะใช้งานจริง: ต้องมีการตรวจสอบการเข้าถึง
  • ชนิดของวัตถุและลำดับชั้นของคลาสนั้นสามารถเปลี่ยนแปลงได้ที่รันไทม์: ต้องตรวจสอบลำดับชั้นของคลาส

เช็คบางส่วนสามารถยกเลิกได้หลังจากการวิเคราะห์ (NB: การวิเคราะห์นี้ยังต้องใช้เวลา - ขณะรันไทม์)

นอกจากนี้ Kos ยังให้เหตุผลว่าภาษาแบบไดนามิกอาจมีประสิทธิภาพมากกว่า C ++ JIT สามารถวิเคราะห์พฤติกรรมของโปรแกรมและใช้การเพิ่มประสิทธิภาพที่เหมาะสม

แต่คอมไพเลอร์ C ++ สามารถทำเช่นเดียวกัน! คอมไพเลอร์สมัยใหม่มีการเพิ่มประสิทธิภาพที่เรียกว่าการแนะนำโปรไฟล์ซึ่งหากได้รับการป้อนข้อมูลที่เหมาะสมสามารถจำลองพฤติกรรมการทำงานของโปรแกรมและใช้การเพิ่มประสิทธิภาพแบบเดียวกับที่ JIT จะนำไปใช้

แน่นอนว่าทั้งหมดนี้มีข้อมูลการฝึกอบรมที่เป็นจริงและนอกจากนี้โปรแกรมไม่สามารถปรับเปลี่ยนลักษณะการทำงานของรันไทม์หากรูปแบบการใช้งานเปลี่ยนไปในระยะกลาง JITs สามารถจัดการเรื่องนี้ในทางทฤษฎี ฉันสนใจที่จะดูว่าค่าโดยสารนี้เป็นอย่างไรในทางปฏิบัติเนื่องจากเพื่อสลับการเพิ่มประสิทธิภาพ JIT จะต้องรวบรวมข้อมูลการใช้งานอย่างต่อเนื่องซึ่งจะทำให้การดำเนินการช้าลงอีกครั้ง

โดยสรุปแล้วฉันไม่เชื่อว่าการออปติไมซ์ฮอตสปอตแบบออปติไมซ์นั้นมีค่ามากกว่าการติดตามข้อมูลรันไทม์ในระยะยาวเมื่อเทียบกับการวิเคราะห์และการเพิ่มประสิทธิภาพแบบสแตติก


2
@ ราฟาเอลนั่นเป็น“ ข้อบกพร่อง” ของคอมไพเลอร์แล้ว โดยเฉพาะอย่างยิ่งjavacการเพิ่มประสิทธิภาพที่แนะนำในโปรไฟล์หรือไม่ ไม่ไกลเท่าที่ฉันรู้ โดยทั่วไปแล้วมันไม่สมเหตุสมผลเลยที่จะทำให้คอมไพเลอร์ของภาษา JITted มีประสิทธิภาพสูงสุดเนื่องจาก JIT สามารถจัดการได้ (และอย่างน้อยที่สุดวิธีนี้ทำให้ภาษามีกำไรมากขึ้นจากความพยายาม) ดังนั้น (เข้าใจได้) ไม่เคยมีความพยายามอย่างมากในเครื่องมือjavacเพิ่มประสิทธิภาพเท่าที่ฉันรู้ (สำหรับภาษา. NET สิ่งนี้เป็นจริงอย่างแน่นอน)
Konrad Rudolph

1
@ ราฟาเอลคำสำคัญ: อาจจะ มันไม่ได้แสดงอย่างใดอย่างหนึ่ง นั่นคือทั้งหมดที่ฉันต้องการจะพูด ฉันได้ให้เหตุผล (แต่ไม่มีข้อพิสูจน์) สำหรับข้อสันนิษฐานของฉันในวรรคก่อน
Konrad Rudolph

1
@Ben ฉันไม่ปฏิเสธว่ามันซับซ้อน นี่เป็นเพียงสัญชาตญาณ การติดตามข้อมูลทั้งหมดที่รันไทม์นั้นมีค่าใช้จ่าย ฉันไม่มั่นใจในประเด็นของคุณเกี่ยวกับ IO หากสิ่งนี้สามารถคาดการณ์ได้ (= กรณีการใช้งานทั่วไป) PGO สามารถทำนายได้ ถ้ามันปลอมฉันไม่เชื่อว่า JIT สามารถปรับมันได้เช่นกัน บางทีนาน ๆ ครั้งโชคไม่ดี แต่น่าเชื่อถือ …
Konrad Rudolph

2
@ Konrad: สัญชาตญาณของคุณเป็นเท็จ มันไม่ได้เกี่ยวกับการที่แตกต่างกันที่รันไทม์ก็เกี่ยวกับการคาดการณ์ที่รวบรวมเวลา จุดที่น่าสนใจสำหรับ JITs กับการปรับให้เหมาะสมแบบคงที่ไม่ใช่เมื่อพฤติกรรมของโปรแกรมเปลี่ยนไปที่รันไทม์ "เร็วเกินไป" สำหรับการทำโปรไฟล์ แต่เมื่อพฤติกรรมของโปรแกรมนั้นง่ายต่อการปรับให้เหมาะสมที่สุดในการทำงานแต่ละโปรแกรม แต่แตกต่างกันไประหว่าง วิ่ง โดยทั่วไปเครื่องมือเพิ่มประสิทธิภาพแบบคงที่จะต้องปรับให้เหมาะสมสำหรับเงื่อนไขชุดเดียวเท่านั้นในขณะที่ JIT จะปรับการทำงานแต่ละครั้งแยกกันสำหรับเงื่อนไขที่เกิดขึ้นในการทำงานนั้น
Ben

3
หมายเหตุ:ข้อคิดเห็นของเธรดนี้กำลังพัฒนาเป็นห้องสนทนาขนาดเล็ก หากคุณต้องการที่จะดำเนินการต่อการสนทนานี้โปรดนำมาสนทนา ความคิดเห็นควรใช้เพื่อปรับปรุงการโพสต์ต้นฉบับ โปรดหยุดการสนทนานี้ที่นี่ ขอบคุณ
Robert Cartaino

20

หากคุณสามารถทำ X ใน C / C ++ พร้อมประสิทธิภาพ Y คุณสามารถทำ X ใน Ruby / Python ที่มีประสิทธิภาพใกล้เคียงกับ Y ได้หรือไม่?

ใช่. ยกตัวอย่างเช่น PyPy มันเป็นคอลเลกชันของรหัส Python ที่ทำงานใกล้กับ C ในการตีความ (ไม่ใช่ทั้งหมดที่อยู่ใกล้ แต่ไม่ใช่ทุกอย่างที่อยู่ไกล) ทำได้โดยการวิเคราะห์โปรแกรมแบบเต็มบนซอร์สโค้ดเพื่อกำหนดตัวแปรแต่ละชนิดให้เป็นสแตติก (ดูที่AnnotatorและRtyper docs สำหรับรายละเอียด) จากนั้นเมื่อติดอาวุธด้วยข้อมูลประเภทเดียวกันที่คุณให้ C มันสามารถทำสิ่งเดียวกันได้ การเพิ่มประสิทธิภาพประเภทต่างๆ อย่างน้อยก็ในทางทฤษฎี

ข้อเสียของหลักสูตรคือมีเพียงชุดย่อยของรหัส Python เท่านั้นที่ยอมรับโดย RPython และโดยทั่วไปแม้ว่าข้อ จำกัด นั้นจะถูกยกขึ้นเพียงชุดย่อยของรหัส Python เท่านั้นที่สามารถทำได้ดี: ชุดย่อยที่สามารถวิเคราะห์และกำหนดประเภทสแตติกได้

หากคุณ จำกัด Python ให้มากที่สุดเครื่องมือเพิ่มประสิทธิภาพสามารถสร้างขึ้นเพื่อใช้ประโยชน์จากเซตย่อยที่ จำกัด และรวบรวมเป็นโค้ดที่มีประสิทธิภาพ นี่ไม่ใช่ผลประโยชน์ที่น่าสนใจจริงๆแล้วมันเป็นที่รู้จักกันดี แต่จุดเริ่มต้นของการใช้ Python (หรือ Ruby) ในตอนแรกคือเราต้องการใช้คุณสมบัติที่น่าสนใจซึ่งอาจวิเคราะห์ได้ไม่ดีและทำให้ได้ประสิทธิภาพที่ดี! ดังนั้นคำถามที่น่าสนใจก็คือ ...

นอกจากนี้คอมไพเลอร์ของ JIT เช่น PyPy / Rubinius จะตรงกับประสิทธิภาพของ C / C ++ หรือไม่

Nah

โดยที่ฉันหมายถึง: แน่นอนว่าเมื่อรหัสสะสมคุณสามารถได้รับข้อมูลการพิมพ์ที่เพียงพอและฮอตสปอตมากพอที่จะรวบรวมรหัสทั้งหมดลงไปจนถึงรหัสเครื่อง และบางทีเราสามารถทำให้นี่ทำงานได้ดีกว่า C สำหรับรหัสบางอย่าง ฉันไม่คิดว่ามันเป็นการโต้เถียงอย่างมหาศาล แต่ก็ยังต้อง "อุ่นเครื่อง" และประสิทธิภาพยังคงคาดเดาได้น้อยกว่าเล็กน้อยและมันจะไม่ดีเท่า C หรือ C ++ สำหรับงานบางอย่างที่ต้องการประสิทธิภาพที่สม่ำเสมอและคาดการณ์ได้สูง

ข้อมูลประสิทธิภาพที่มีอยู่สำหรับ Java ซึ่งมีทั้งข้อมูลประเภทมากกว่า Python หรือ Ruby และคอมไพเลอร์ JIT ที่พัฒนาแล้วดีกว่า Python หรือ Ruby แต่ยังไม่ตรงกับ C / C ++ มันเป็นอย่างไรในสนามเบสบอลเดียวกัน


1
"ข้อเสียของหลักสูตรคือยอมรับเฉพาะชุดโค้ดไพ ธ อนเท่านั้นหรือชุดโค้ดไพ ธ อนชุดย่อยเท่านั้นที่ทำได้ดี: ชุดย่อยที่สามารถวิเคราะห์และกำหนดประเภทสแตติกได้" มันไม่ถูกต้องนัก เฉพาะชุดย่อยเท่านั้นที่สามารถยอมรับได้โดยคอมไพเลอร์ RPython การคอมไพล์ไปยัง RPython ให้มีประสิทธิภาพอย่างสมเหตุสมผล C จะทำงานได้อย่างแม่นยำเพราะส่วนที่ยากต่อการคอมไพล์ของ Python นั้นรับประกันว่าจะไม่เกิดขึ้นในโปรแกรม RPython ไม่ใช่เพียงว่าหากเกิดขึ้นพวกเขาจะไม่ได้รับการปรับให้เหมาะสม มันเป็นล่ามที่รวบรวมซึ่งจัดการ Python ทั้งหมด
Ben

1
เกี่ยวกับ JIT: ฉันได้เห็นมากกว่าหนึ่งมาตรฐานที่ Java ได้ดีกว่าหลายรสชาติของ C (++) เฉพาะ C ++ ที่มีการเพิ่มดูเหมือนว่าจะอยู่ข้างหน้าอย่างน่าเชื่อถือ ในกรณีนั้นฉันสงสัยว่าประสิทธิภาพต่อเวลาของนักพัฒนา แต่เป็นอีกหัวข้อ
Raphael

@Ben: เมื่อคุณมี RPython มันเป็นเรื่องง่ายที่จะสร้างคอมไพเลอร์ / ล่ามที่กลับไปใช้ CPython interpreter เมื่อคอมไพเลอร์ RPython ล้มเหลวดังนั้น "เพียงส่วนย่อยของรหัส Python ที่สามารถทำได้ดี: ... " มีความถูกต้องทั้งหมด
Lie Ryan

9
@Raphael มันถูกแสดงหลายครั้งที่เขียนโค้ด C ++ ได้ดีกว่า Java เป็นส่วน "เขียนดี" ที่ค่อนข้างยากที่จะได้รับใน C ++ ดังนั้นในม้านั่งหลายแห่งที่คุณเห็นผลลัพธ์ที่ Java มีประสิทธิภาพสูงกว่า C ++ ดังนั้น C ++ จึงมีราคาแพงกว่า แต่เมื่อต้องการการควบคุม mem ที่แน่นและกรวดโลหะที่มีความจำเป็น C / C ++ คือสิ่งที่คุณต้องการ โดยเฉพาะ C เป็นเพียงตัวประกอบ ac / p
TC1

7
การเปรียบเทียบประสิทธิภาพสูงสุดของภาษาอื่น ๆ กับภาษาเช่น C / C ++ เป็นการออกกำลังกายที่ไร้ประโยชน์เนื่องจากคุณสามารถอินไลน์แอสเซมบลีโดยตรงเป็นส่วนหนึ่งของข้อกำหนดภาษา อะไรก็ตามที่เครื่องสามารถรันโปรแกรมที่เขียนด้วยภาษาใดก็ได้คุณสามารถทำซ้ำที่เลวร้ายที่สุดได้โดยการเขียนชุดประกอบจากร่องรอยของคำสั่งที่เรียกใช้งาน ตัวชี้วัดที่น่าสนใจกว่านั้นก็คือ @Raphael แนะนำในความคิดเห็นก่อนหน้านี้ประสิทธิภาพต่อการพัฒนาความพยายาม (ชั่วโมงคนบรรทัดของรหัส ฯลฯ )
Patrick87

18

คำตอบสั้น ๆ คือ: เราไม่รู้ถามอีกครั้งใน 100 ปี (เราอาจยังไม่รู้อยู่ดี; อาจเป็นไปไม่ได้เลย)

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

จากนั้นอีกครั้งในทางทฤษฎีภาษาระดับสูงอาจสามารถเข้าถึงประสิทธิภาพของรหัสเครื่องได้ แต่ก็ไม่สามารถทำได้ นี่ยังคงเป็นเชิงทฤษฎีมากเพราะในแง่ปฏิบัติเราไม่ค่อยใช้วิธีเขียนรหัสเครื่องจักร อาร์กิวเมนต์นี้ใช้ไม่ได้กับการเปรียบเทียบภาษาระดับสูงกว่า: มันไม่ได้หมายความว่า C ต้องมีประสิทธิภาพมากกว่า Python เท่านั้นที่รหัสเครื่องไม่สามารถทำได้แย่กว่า Python

จากด้านอื่น ๆ ในแง่ของการทดลองล้วนๆเราจะเห็นได้ว่าส่วนใหญ่การตีความภาษาระดับสูงนั้นมีประสิทธิภาพแย่กว่าภาษาระดับต่ำที่รวบรวม เรามักจะเขียนโค้ดที่ไม่ไวต่อเวลาในภาษาระดับสูงมากและวงภายในที่สำคัญในการประกอบโดยมีภาษาอย่าง C และ Python หล่นลงมา แม้ว่าฉันจะไม่มีสถิติในการสำรองสิ่งนี้ แต่ฉันคิดว่านี่เป็นการตัดสินใจที่ดีที่สุดในกรณีส่วนใหญ่

อย่างไรก็ตามมีอินสแตนซ์ที่ไม่มีการโต้แย้งที่ภาษาระดับสูงใช้รหัสที่คนจะเขียนจริง: สภาพแวดล้อมการเขียนโปรแกรมวัตถุประสงค์พิเศษ โปรแกรมเช่น Matlab และ Mathematica มักจะดีกว่าที่จะแก้ปัญหาทางคณิตศาสตร์บางชนิดได้ดีกว่าสิ่งที่มนุษย์สามารถเขียนได้ ฟังก์ชั่นห้องสมุดอาจถูกเขียนใน C หรือ C ++ (ซึ่งเป็นเชื้อเพลิงต่อค่าย“ ภาษาระดับต่ำมีประสิทธิภาพมากขึ้น”) แต่นั่นไม่ใช่ธุรกิจของฉันถ้าฉันเขียนรหัส Mathematica ห้องสมุดเป็นกล่องดำ

เป็นไปได้ในทางทฤษฎีหรือไม่ว่างูใหญ่จะเข้าใกล้หรืออาจยิ่งใกล้กว่าเพื่อประสิทธิภาพที่ดีที่สุดกว่า C? เท่าที่เห็นข้างต้นใช่ แต่เราอยู่ห่างไกลจากวันนี้มาก จากนั้นอีกครั้งคอมไพเลอร์มีความก้าวหน้าอย่างมากในทศวรรษที่ผ่านมาและความคืบหน้านั้นไม่ได้ชะลอตัวลง

ภาษาระดับสูงมีแนวโน้มที่จะทำให้สิ่งต่าง ๆ เป็นไปโดยอัตโนมัติมากขึ้นดังนั้นพวกเขาจึงมีงานที่ต้องทำมากขึ้นและทำให้มีประสิทธิภาพน้อย ในทางกลับกันพวกเขามีแนวโน้มที่จะมีข้อมูลเชิงความหมายมากขึ้นดังนั้นจึงสามารถสังเกตเห็นการปรับให้เหมาะสมได้ง่ายขึ้น (ถ้าคุณเขียนคอมไพเลอร์ Haskell คุณไม่ต้องกังวลว่าอีกเธรดหนึ่งจะแก้ไขตัวแปรใต้จมูกของคุณ) หนึ่งในหลาย ๆ ความพยายามในการเปรียบเทียบแอปเปิ้ลและส้มภาษาการเขียนโปรแกรมที่แตกต่างกันคือเกมเกณฑ์มาตรฐานภาษาคอมพิวเตอร์ (เดิมชื่อจุดโทษ) Fortran มีแนวโน้มที่จะส่องแสงในงานตัวเลข; แต่เมื่อพูดถึงการจัดการข้อมูลที่มีโครงสร้างหรือการแลกเปลี่ยนเธรดอัตราสูง, F # และ Scala ทำได้ดี อย่านำผลลัพธ์เหล่านี้มาเป็นข่าวประเสริฐ: สิ่งที่พวกเขากำลังวัดจำนวนมากคือผู้เขียนโปรแกรมทดสอบในแต่ละภาษานั้นดีเพียงใด

ข้อโต้แย้งในความโปรดปรานของภาษาระดับสูงคือประสิทธิภาพของระบบที่ทันสมัยนั้นไม่มีความสัมพันธ์อย่างมากกับจำนวนคำสั่งที่ถูกเรียกใช้งานและเมื่อเวลาผ่านไปน้อยลง ภาษาระดับต่ำนั้นเหมาะสำหรับเครื่องจักรแบบง่าย หากภาษาระดับสูงดำเนินการตามคำแนะนำได้มากเป็นสองเท่า แต่จัดการเพื่อใช้แคชอย่างชาญฉลาดมากขึ้นเพื่อให้แคชหายไปครึ่งหนึ่งก็อาจจบลงด้วยการชนะ

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

โดยรวมในขณะที่ภาษาระดับสูงเริ่มต้นด้วยการลงโทษพวกเขามีห้องพักมากขึ้นสำหรับการปรับปรุง พวกเขาได้ใกล้แค่ไหน ถามอีกครั้งใน 100 ปี

หมายเหตุสุดท้าย: บ่อยครั้งการเปรียบเทียบไม่ใช่ระหว่างโปรแกรมที่มีประสิทธิภาพที่สุดที่สามารถเขียนด้วยภาษา A และเป็นภาษาเดียวกัน B หรือระหว่างโปรแกรมที่มีประสิทธิภาพมากที่สุดที่เคยเขียนในแต่ละภาษา แต่ระหว่างโปรแกรมที่มีประสิทธิภาพที่สุดที่สามารถเขียนได้ โดยมนุษย์ในระยะเวลาหนึ่งในแต่ละภาษา สิ่งนี้แนะนำองค์ประกอบที่ไม่สามารถวิเคราะห์ทางคณิตศาสตร์ได้แม้ในหลักการ ในแง่การปฏิบัติสิ่งนี้มักหมายความว่าประสิทธิภาพที่ดีที่สุดคือการประนีประนอมระหว่างโค้ดระดับต่ำที่คุณต้องเขียนเพื่อให้บรรลุเป้าหมายด้านประสิทธิภาพและโค้ดระดับต่ำที่คุณมีเวลาเขียนให้ตรงกับวันที่วางจำหน่าย


ฉันคิดว่าความแตกต่างระหว่างระดับสูงกับระดับต่ำเป็นสิ่งที่ผิด C ++ สามารถอยู่ในระดับสูงมาก ถึงกระนั้น C ++ ระดับสูงที่ทันสมัยก็ไม่ได้มีประสิทธิภาพที่เลวร้ายยิ่งกว่าการเทียบเท่าระดับต่ำ C ++ และห้องสมุดได้รับการออกแบบอย่างพิถีพิถันเพื่อให้เป็นนามธรรมระดับสูงโดยไม่มีการลงโทษ สิ่งเดียวกันสำหรับตัวอย่าง Haskell ของคุณ: abstractions ระดับสูงมักเปิดใช้งานแทนที่จะป้องกันการเพิ่มประสิทธิภาพ ความแตกต่างดั้งเดิมระหว่างภาษาไดนามิกและภาษาแบบคงที่ทำให้มีเหตุผลมากขึ้นในเรื่องนี้
Konrad Rudolph

@ KonradRudolph คุณพูดถูกในระดับต่ำ / ระดับสูงนั้นเป็นความแตกต่างโดยพลการ แต่ภาษาแบบไดนามิกและแบบคงที่ไม่ได้จับทุกอย่างเช่นกัน JIT สามารถขจัดความแตกต่างได้มาก โดยพื้นฐานแล้วคำตอบเชิงทฤษฎีที่ทราบกันดีสำหรับคำถามนี้นั้นเล็กน้อยและไร้ประโยชน์และคำตอบที่ใช้ได้คือ“ มันขึ้นอยู่กับ”
Gilles

จากนั้นฉันคิดว่าคำถามจะกลายเป็น“ JIT จะกลายเป็นดีแค่ไหนและถ้าพวกเขาแซงการรวบรวมแบบคงที่ภาษาที่รวบรวมแบบคงที่จะได้รับประโยชน์จากพวกเขาด้วย” อย่างน้อยนั่นคือสิ่งที่ฉันเข้าใจคำถามเมื่อเราพิจารณา JIT และใช่ฉันเห็นด้วยกับการประเมินของคุณ แต่แน่นอนว่าเราจะได้รับการคาดเดาข้อมูลบางอย่างซึ่งเกินกว่า“ มันขึ้นอยู่กับ” ;-)
Konrad Rudolph

@KonradRudolph ถ้าผมต้องการที่คาดเดาผมถามเกี่ยวกับวิศวกรรมซอฟต์แวร์
Gilles

1
น่าเสียดายที่การถ่ายภาพภาษาเป็นแหล่งที่น่าสงสัยสำหรับการวัดเชิงปริมาณ: พวกเขาไม่ยอมรับโปรแกรมทั้งหมดเฉพาะที่เห็นว่าเป็นเรื่องปกติของภาษา นี่เป็นข้อกำหนดที่ยุ่งยากและเป็นอัตนัย หมายความว่าคุณไม่สามารถสันนิษฐานได้ว่าการติดตั้งระบบยิงนั้นจริง ๆ แล้วเป็นเรื่องที่ดี ด้านพลิก; สิ่งเหล่านี้คือ microbenchmarks และการใช้งานบางอย่างใช้เทคนิคที่ผิดปกติซึ่งคุณไม่เคยพิจารณาในสถานการณ์ปกติมากขึ้นเพียงเพื่อให้ได้ประสิทธิภาพ ดังนั้นมันจึงเป็นเกมไม่ใช่แหล่งข้อมูลที่น่าเชื่อถือมาก
Eamon Nerbonne

10

ความแตกต่างขั้นพื้นฐานระหว่าง c ++ คำสั่งx = a + bและคำสั่ง Python x = a + bเป็นที่ C / C ++ คอมไพเลอร์สามารถบอกได้จากคำสั่งนี้ (และข้อมูลเพิ่มเติมเล็กน้อยว่ามีพร้อมเกี่ยวกับประเภทของx, aและb) สิ่งที่รหัสเครื่องจะต้องมีการดำเนินการ . โดยที่จะบอกว่าการดำเนินการของคำสั่ง Python นั้นคืออะไรคุณต้องแก้ไขปัญหาการหยุดงาน

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

ในหลาม, คอมไพเลอร์ในทางทฤษฎีสามารถทำเกือบที่ดีถ้ามันรู้ว่าaและbทั้งสองints มีค่าใช้จ่ายในการชกมวยเพิ่มเติมบางส่วน แต่ถ้าประเภทเป็นที่รู้จักกันแบบคงที่คุณอาจกำจัดได้เช่นกัน (ในขณะที่ยังคงแสดงอินเทอร์เฟซที่จำนวนเต็มเป็นวัตถุที่มีวิธีการลำดับชั้นของซุปเปอร์คลาส ฯลฯ ) ปัญหาคือคอมไพเลอร์สำหรับ Python ไม่สามารถทำได้รู้เรื่องนี้เนื่องจากคลาสถูกกำหนดที่รันไทม์สามารถแก้ไขได้ที่รันไทม์และแม้แต่โมดูลที่ทำการกำหนดและอิมพอร์ตจะถูกแก้ไขที่รันไทม์ (และแม้แต่คำสั่งการนำเข้าที่ถูกเรียกใช้ขึ้นอยู่กับสิ่งที่สามารถรู้ได้เฉพาะตอนรันไทม์) ดังนั้นคอมไพเลอร์ Python จะต้องรู้ว่าโค้ดใดที่ถูกประมวลผล (เช่นแก้ปัญหาการหยุดชะงัก) เพื่อที่จะทราบว่าคำสั่งที่คอมไพล์รวบรวมจะทำอะไร

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

โปรดทราบว่านี้ไม่ได้ขึ้นอยู่กับสิ่งที่รหัสจะทำมันขึ้นอยู่กับสิ่งที่รหัสอาจจะทำ แม้แต่รหัสไพ ธ อนที่เป็นชุดของการดำเนินการทางคณิตศาสตร์เลขจำนวนเต็มอย่างเรียบง่ายจะต้องมีการรวบรวมราวกับว่ามันอาจจะเรียกการดำเนินงานในชั้นเรียนโดยพลการ ภาษาแบบคงที่มีข้อ จำกัด ที่มากขึ้นเกี่ยวกับความเป็นไปได้สำหรับสิ่งที่รหัสสามารถทำได้และดังนั้นคอมไพเลอร์ของพวกเขาสามารถตั้งสมมติฐานได้มากขึ้น

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

มีคอมไพเลอร์ JIT ต่าง ๆ สำหรับภาษาแบบไดนามิกที่อ้างว่าเพื่อให้บรรลุความเร็วในการดำเนินการเทียบเท่ากับภาษา C / C ++ ที่คอมไพล์และปรับให้เหมาะสม มีการปรับให้เหมาะสมที่สุดที่สามารถทำได้โดยคอมไพเลอร์ JIT ที่ไม่สามารถทำได้โดยคอมไพเลอร์ก่อนเวลาสำหรับภาษาใด ๆ ดังนั้นการรวบรวม JIT ตามหลักวิชา (สำหรับบางโปรแกรม) ในทางทฤษฎีอาจมีประสิทธิภาพมากกว่าในหนึ่งวัน แต่เมื่อ Devin ชี้ให้เห็นอย่างถูกต้องคุณสมบัติของการรวบรวม JIT (เฉพาะ "ฮอตสปอต" นั้นมีความรวดเร็วและหลังจากช่วงเวลาวอร์มอัพ) หมายความว่าภาษาแบบไดนามิกที่รวบรวมโดย JIT นั้นไม่น่าจะเหมาะสำหรับการใช้งานที่เป็นไปได้ทั้งหมด เร็วหรือเร็วกว่าภาษาที่รวบรวมโดยทั่วไป


1
นั่นคือตอนนี้โหวตสองครั้งโดยไม่มีความเห็น ฉันยินดีรับข้อเสนอแนะสำหรับวิธีการปรับปรุงคำตอบนี้!
Ben

ฉันไม่ได้ลงคะแนน แต่คุณไม่ถูกต้องเกี่ยวกับ "ต้องแก้ปัญหาการหยุดพัก" มันได้รับการพิสูจน์แล้วในหลาย ๆ สถานการณ์ว่าโค้ดในภาษาไดนามิกสามารถคอมไพล์ไปยังโค้ดเป้าหมายที่ดีที่สุดในขณะที่ความรู้ของฉันไม่มีการสาธิตเหล่านี้ได้รวมวิธีการแก้ปัญหาการหยุด :-)
mikera

@ Mikera ฉันขอโทษ แต่ไม่คุณไม่ถูกต้อง ไม่มีใครเคยใช้คอมไพเลอร์ (ในแง่ที่เราเข้าใจว่า GCC เป็นคอมไพเลอร์) สำหรับPython ทั่วไปหรือภาษาไดนามิกอื่น ๆ ทุกระบบดังกล่าวใช้งานได้กับชุดย่อยของภาษาหรือเฉพาะบางโปรแกรมเท่านั้นหรือบางครั้งก็ปล่อยรหัสที่โดยทั่วไปคือล่ามที่มีโปรแกรมฮาร์ดโค้ด หากคุณต้องการฉันจะเขียนโปรแกรม Python ที่มีบรรทัดfoo = x + yที่ทำนายพฤติกรรมของตัวดำเนินการเพิ่มในเวลารวบรวมขึ้นอยู่กับการแก้ปัญหาการหยุดชะงัก
เบ็น

ฉันถูกต้องและฉันคิดว่าคุณไม่มีจุด ฉันพูดว่า "ในหลาย ๆ สถานการณ์" ฉันไม่ได้พูดว่า "ในทุกสถานการณ์ที่เป็นไปได้" ไม่ว่าคุณจะสามารถสร้างตัวอย่างที่วางแผนไว้ซึ่งเชื่อมโยงกับปัญหาการหยุดชะงักหรือไม่นั้นส่วนใหญ่ไม่เกี่ยวข้องในโลกแห่งความเป็นจริง FWIW คุณสามารถสร้างตัวอย่างที่คล้ายกันสำหรับ C ++ ดังนั้นคุณจะไม่ได้พิสูจน์อะไรเลย อย่างไรก็ตามฉันไม่ได้มาที่นี่เพื่อโต้เถียงเพื่อแนะนำการปรับปรุงคำตอบของคุณ เอามันหรือปล่อยให้มัน.
mikera

@ikea ฉันคิดว่าคุณอาจพลาดประเด็นนี้ไป เพื่อรวบรวมx + yการดำเนินการเพิ่มเครื่องจักรที่มีประสิทธิภาพคุณจำเป็นต้องรู้เวลารวบรวมว่ามันเป็นหรือไม่ ตลอดเวลาไม่ใช่แค่บางครั้ง สำหรับภาษาไดนามิกนั้นแทบจะเป็นไปไม่ได้สำหรับโปรแกรมที่ใช้งานจริงแม้ว่าฮิวริสติกที่สมเหตุสมผลจะคาดเดาได้เกือบตลอดเวลา รวบรวมต้องใช้เวลารวบรวมค้ำประกัน ดังนั้นโดยการพูดถึง "ในหลาย ๆ สถานการณ์" คุณไม่ได้ตอบคำถามของฉันเลย
เบ็น

9

ตัวชี้ด่วนที่สรุปสถานการณ์กรณีเลวร้ายที่สุดสำหรับภาษาแบบไดนามิก:

การแยกวิเคราะห์ Perl ไม่สามารถคำนวณได้

ดังนั้น Perl (เต็ม) จึงไม่สามารถรวบรวมแบบคงที่ได้


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

สิ่งที่ควรทราบอีกประการหนึ่งคือภาษาแบบไดนามิกแก้ปัญหาอื่นได้มากกว่า C. C แทบจะไม่มากกว่าไวยากรณ์ที่ดีสำหรับแอสเซมเบลอร์ในขณะที่ภาษาแบบไดนามิกให้นามธรรมที่สมบูรณ์ ตัวอย่างเช่นประสิทธิภาพของรันไทม์ไม่ได้เป็นประเด็นสำคัญเช่นเวลาสู่ตลาดขึ้นอยู่กับนักพัฒนาของคุณที่สามารถเขียนระบบที่ซับซ้อนและมีคุณภาพสูงในกรอบเวลาสั้น ๆ ความสามารถในการขยายที่ไม่มีการคอมไพล์ซ้ำเช่นกับปลั๊กอินเป็นอีกคุณสมบัติที่ได้รับความนิยม คุณชอบภาษาใดในกรณีนี้


5

ในความพยายามที่จะเสนอคำตอบทางวิทยาศาสตร์ที่เป็นกลางมากขึ้นกับคำถามนี้ฉันเถียงดังนี้ ภาษาแบบไดนามิกต้องใช้ล่ามหรือรันไทม์เพื่อการตัดสินใจในเวลาทำงาน ล่ามหรือรันไทม์นี้เป็นโปรแกรมคอมพิวเตอร์และเช่นนั้นถูกเขียนในภาษาการเขียนโปรแกรมบางส่วนทั้งแบบคงที่หรือแบบไดนามิก

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

สมมติว่าการอ้างสิทธิ์เหล่านี้เป็นจริงทางออกเดียวคือต้องการให้ล่าม / รันไทม์เขียนด้วยภาษาแบบไดนามิกเช่นกัน อย่างไรก็ตามเราพบปัญหาเดียวกันกับก่อนหน้านี้: หากล่ามเป็นแบบไดนามิกจำเป็นต้องมีล่าม / รันไทม์ซึ่งต้องเขียนด้วยภาษาการเขียนโปรแกรมแบบไดนามิกหรือแบบคงที่

เว้นแต่คุณจะสันนิษฐานว่าอินสแตนซ์ของล่ามมีความสามารถในการตีความตัวเองที่รันไทม์ (ฉันหวังว่านี่เป็นเรื่องไร้สาระที่เห็นได้ชัดในตัวเอง) วิธีเดียวที่จะเอาชนะภาษาคงที่ได้คือการแปลอินสแตนซ์ล่าม สิ่งนี้นำไปสู่การถดถอยที่ไม่สิ้นสุด (ฉันหวังว่านี่เป็นเรื่องไร้สาระที่เห็นได้ชัดในตัวเอง) หรือเป็นล่ามวงปิด (ฉันหวังว่านี่จะเป็นเรื่องไร้สาระที่เห็นได้ชัดด้วยตนเอง)

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

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

อีกวิธีหนึ่งในการตอบคำถามในแง่ของการสนทนานี้คือ: ในโปรแกรมการจัดเก็บข้อมูล = การควบคุมแบบจำลองการคำนวณซึ่งอยู่ที่หัวใจของการคำนวณสมัยใหม่ความแตกต่างระหว่างการรวบรวมแบบไดนามิกและแบบคงที่คือ ภาษาที่รวบรวมแบบสแตติกต้องมีวิธีในการสร้างและเรียกใช้รหัสโดยอำเภอใจในเวลาทำงาน มันเป็นพื้นฐานที่เกี่ยวข้องกับการคำนวณสากล


อ่านนี่ฉันไม่คิดว่ามันเป็นเรื่องจริง การรวบรวม JIT ทำให้คุณทะเลาะกัน แม้แต่โค้ดที่ง่ายที่สุดเช่นmain(args) { for ( i=0; i<1000000; i++ ) { if ( args[0] == "1" ) {...} else {...} }สามารถเร่งความเร็วได้อย่างมีนัยสำคัญเมื่อทราบค่าargs(สันนิษฐานว่ามันไม่เคยเปลี่ยนแปลงซึ่งเราอาจยืนยันได้) คอมไพเลอร์แบบสแตติกไม่สามารถสร้างรหัสที่ลดการเปรียบเทียบได้ (แน่นอนว่าในตัวอย่างนั้นคุณเพิ่งดึงวงifออกมา แต่สิ่งนี้อาจซับซ้อนกว่านี้)
Raphael

@ ราฟาเอลฉันคิดว่า JIT อาจทำให้การโต้แย้งของฉัน โปรแกรมที่ทำการคอมไพล์ JIT (เช่น JVM) เป็นโปรแกรมที่คอมไพล์แบบสแตติก หากโปรแกรม JIT ที่รวบรวมแบบสแตติกสามารถรันสคริปต์ได้เร็วกว่าโปรแกรมแบบสแตติกอื่น ๆ ที่สามารถทำงานเดียวกันเพียงแค่ "รวมกลุ่ม" สคริปต์ด้วยตัวรวบรวม JIT และเรียกใช้โปรแกรมที่รวบรวมแบบสแตติก สิ่งนี้จะต้องทำอย่างน้อยเช่นเดียวกับ JIT ที่ทำงานในโปรแกรมแบบไดนามิกแยกต่างหากขัดแย้งกับข้อโต้แย้งใด ๆ ที่ JIT ต้องทำดีกว่า
Patrick87

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

@ ราฟาเอลที่ไม่มีความแตกต่างที่มีความหมายนั้นเป็นจุดของคำตอบ: ความพยายามใด ๆ ในการจำแนกภาษาอย่างเข้มงวดบางอย่างเป็นแบบสแตติกและทำให้ทรมานจากข้อ จำกัด ด้านประสิทธิภาพล้มเหลวด้วยเหตุผลนี้: ไม่มีความแตกต่างที่น่าสนใจ , สคริปต์) บันเดิลและโปรแกรม C ถ้า (Ruby, script) สามารถทำให้เครื่องรันลำดับที่ถูกต้องของคำสั่งเพื่อแก้ปัญหาที่กำหนดได้อย่างมีประสิทธิภาพดังนั้นโปรแกรม C ที่ออกแบบมาอย่างชาญฉลาดสามารถ
Patrick87

แต่คุณสามารถกำหนดความแตกต่าง ตัวแปรหนึ่งส่งรหัสในมือถึงโปรเซสเซอร์ที่ไม่เปลี่ยนแปลง (C), คอมไพล์อื่น ๆ ที่รันไทม์ (Ruby, Java, ... ) สิ่งแรกคือสิ่งที่เราหมายถึงโดย "การรวบรวมแบบคงที่" ในขณะที่สิ่งหลังจะเป็น "การรวบรวมแบบทันเวลา" (ซึ่งจะช่วยให้การเพิ่มประสิทธิภาพข้อมูลขึ้นอยู่กับข้อมูล)
Raphael

4

คุณสามารถสร้างคอมไพเลอร์สำหรับภาษาไดนามิกเช่น Ruby เพื่อให้มีประสิทธิภาพที่คล้ายกันและเทียบเท่ากับ C / C ++ ได้หรือไม่?

ผมคิดว่าคำตอบที่"ใช่" ฉันยังเชื่อว่าพวกเขาสามารถทำได้ดีกว่าสถาปัตยกรรม C / C ++ ปัจจุบันในแง่ของประสิทธิภาพ (แม้ว่าจะเล็กน้อย)

เหตุผลง่าย: มีข้อมูลเพิ่มเติมในเวลาทำงานมากกว่าในเวลารวบรวม

ประเภทไดนามิกเป็นเพียงอุปสรรคเล็กน้อย: หากฟังก์ชั่นถูกดำเนินการเสมอหรือเกือบตลอดเวลาด้วยประเภทอาร์กิวเมนต์เดียวกันดังนั้นเครื่องมือเพิ่มประสิทธิภาพ JIT สามารถสร้างสาขาและรหัสเครื่องสำหรับกรณีเฉพาะ และยังมีอีกมากที่สามารถทำได้

ดูDynamic Languages ​​Strike Backคำพูดของ Steve Yegge ของ Google (นอกจากนี้ยังมีวิดีโอเวอร์ชันที่ฉันเชื่อ) เขากล่าวถึงเทคนิคการเพิ่มประสิทธิภาพ JIT ที่เป็นรูปธรรมบางอย่างจาก V8 สร้างแรงบันดาลใจ!

ฉันรอคอยสิ่งที่เราจะได้รับในอีก 5 ปีข้างหน้า!


2
ฉันรักการมองในแง่ดี
Dave Clarke

ฉันเชื่อว่ามีการวิพากษ์วิจารณ์บางอย่างที่เฉพาะเจาะจงของความไม่ถูกต้องในการพูดคุยของสตีฟ ฉันจะโพสต์พวกเขาเมื่อฉันพบพวกเขา
Konrad Rudolph

1
@DaveClarke นั่นคือสิ่งที่ทำให้ฉันทำงาน :)
Kos

2

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

  • สัญลักษณ์ (vars หรือค่อนข้าง id <-> การผูกตัวเลขทุกชนิด) ถูกยกเลิกการพิมพ์
  • โครงสร้าง (ข้อมูลสิ่งมีชีวิตทั้งหมดในรันไทม์) ถูกยกเลิกการพิมพ์เช่นกันตามประเภทขององค์ประกอบ

จุดที่สองให้ความเป็นอิสระได้ฟรี โปรดทราบว่าโครงสร้างที่นี่คือองค์ประกอบประกอบคอลเลกชัน แต่ยังพิมพ์ตัวเองและแม้กระทั่ง (!) กิจวัตรทุกชนิด (ฟังก์ชั่นการกระทำการดำเนินงาน) ... เราสามารถพิมพ์โครงสร้างตามประเภทองค์ประกอบของพวกเขา แต่เนื่องจากจุดแรก ตรวจสอบจะเกิดขึ้นที่รันไทม์อยู่แล้ว เราจะได้พิมพ์สัญลักษณ์และยังคงมีโครงสร้างคน untyped ตามประเภทองค์ประกอบของพวกเขา (อาเรย์aก็จะพิมพ์เป็นแถวไม่เป็นอาร์เรย์ของ ints เป็นนัก) แต่ถึงแม้จะไม่กี่นี้ไม่เป็นความจริงในภาษาแบบไดนามิก ( aรวมทั้งอาจมี สตริง).

L

  • ElementLLในรูปแบบ)
  • สัญลักษณ์ทั้งหมดเป็นประเภทElementนั้นพวกเขาสามารถเก็บองค์ประกอบของใด ๆLชนิด
  • โครงสร้างทั้งหมด (อีกครั้งรวมถึงรูทีนโมเดล) ได้รับเฉพาะอิลิเมนต์

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


+1 น่าสนใจมาก คุณอ่านคำตอบของฉัน ความคิดของคุณและฉันดูเหมือนจะคล้ายกันแม้ว่าคำตอบของคุณจะให้รายละเอียดเพิ่มเติมและมุมมองที่น่าสนใจ
Patrick87

ภาษาไดนามิกไม่จำเป็นต้องยกเลิกการพิมพ์ การนำโมเดลภาษาไดนามิกไปใช้ใน C จะ จำกัด ความเป็นไปได้ในการเพิ่มประสิทธิภาพอย่างรุนแรง มันทำให้ยากสำหรับคอมไพเลอร์ที่จะรับรู้การเพิ่มประสิทธิภาพในระดับสูง (เช่นข้อมูลที่ไม่เปลี่ยนรูป) และบังคับให้การดำเนินงานพื้นฐานบางอย่าง (เช่นการเรียกใช้ฟังก์ชั่น) ผ่าน C สิ่งที่คุณอธิบายไม่ไกลจากล่าม bytecode preevaluated; คอมไพเลอร์ดั้งเดิมมีแนวโน้มที่จะทำงานได้ดีขึ้นอย่างมีนัยสำคัญฉันสงสัยว่าการถอดรหัส bytecode สามารถพิสูจน์ความแตกต่างได้
Gilles

@ Patrick87: ถูกต้องแนวความคิดของเราดูเหมือนคล้ายกันมาก (ไม่เคยอ่านมาก่อนขออภัยการสะท้อนกลับของฉันมาจากการใช้ dyn lang ใน C)
spir

@Gilles: ฉันค่อนข้างเห็นด้วยกับ "... ไม่จำเป็นต้องพิมพ์" ถ้าคุณหมายถึงไม่พิมพ์แบบคงที่ แต่นี่ไม่ใช่สิ่งที่ผู้คนคิดกันว่า dyn langs โดยทั่วไปฉันคิดว่า ฉันพิจารณาความใจดีโดยทั่วไป (ตามความหมายทั่วไปที่ให้ไว้ในคำตอบข้างต้น) คุณลักษณะที่ทรงพลังยิ่งกว่าและยากกว่าที่จะอยู่โดยปราศจาก เราสามารถหาวิธีที่จะทำกับประเภทคงที่ได้อย่างง่ายดายโดยขยายความคิดของเราเกี่ยวกับวิธีการกำหนดประเภท (ดูเหมือน polymorphic) ที่กำหนดหรือโดยให้ความยืดหยุ่นกับอินสแตนซ์โดยตรง
spir

1

ฉันไม่มีเวลาอ่านรายละเอียดทั้งหมดโดยละเอียด ... แต่ฉันก็รู้สึกสนุก

มีความขัดแย้งที่คล้ายกันในอายุหกสิบเศษและอายุเจ็ดสิบต้น (ประวัติศาสตร์วิทยาศาสตร์คอมพิวเตอร์มักจะทำซ้ำตัวเอง): ภาษาระดับสูงสามารถรวบรวมเพื่อผลิตรหัสที่มีประสิทธิภาพเป็นรหัสเครื่องดีพูดประกอบรหัสผลิตโดยโปรแกรมเมอร์ ทุกคนรู้ว่าโปรแกรมเมอร์นั้นฉลาดกว่าโปรแกรมใด ๆ และสามารถสร้างการเพิ่มประสิทธิภาพที่ชาญฉลาดได้ (คิดว่าจริงๆแล้วสิ่งที่เรียกว่าการเพิ่มประสิทธิภาพช่องมอง) แน่นอนนี่เป็นการประชดในส่วนของฉัน

แม้กระทั่งแนวคิดของการขยายโค้ด: อัตราส่วนของขนาดของโค้ดที่คอมไพเลอร์สร้างขึ้นกับขนาดของโค้ดสำหรับโปรแกรมเดียวกันที่สร้างโดยโปรแกรมเมอร์ที่ดี (ราวกับว่ามันมีมากเกินไป :-) แน่นอนว่าความคิดคืออัตราส่วนนี้มากกว่า 1 เสมอภาษาของเวลาคือ Cobol และ Fortran 4 หรือ Algol 60 สำหรับปัญญาชน ฉันเชื่อว่าเสียงกระเพื่อมไม่ได้รับการพิจารณา

มีข่าวลือว่ามีใครบางคนสร้างคอมไพเลอร์ที่บางครั้งอาจมีอัตราส่วนการขยายตัวที่ 1 ... จนกระทั่งมันกลายเป็นกฎที่คอมไพล์โค้ดได้ดีกว่าโค้ดที่เขียนด้วยมือ (และเชื่อถือได้มากกว่า) ผู้คนกังวลเกี่ยวกับขนาดของรหัสในช่วงเวลานั้น (ความทรงจำเล็ก ๆ ) แต่สิ่งเดียวกันก็เพื่อความรวดเร็วหรือการสิ้นเปลืองพลังงาน ฉันจะไม่ไปด้วยเหตุผล

คุณสมบัติแปลกประหลาดคุณสมบัติแบบไดนามิกของภาษาไม่สำคัญ สิ่งสำคัญคือวิธีใช้งานไม่ว่าจะใช้ ประสิทธิภาพไม่ว่าจะเป็นหน่วยใด (ขนาดรหัสความเร็วพลังงาน ... ) มักขึ้นอยู่กับส่วนเล็ก ๆ ของโปรแกรม ดังนั้นจึงเป็นโอกาสที่ดีที่สิ่งอำนวยความสะดวกที่ให้พลังในการแสดงออกจะไม่เข้าทาง ด้วยการฝึกการเขียนโปรแกรมที่ดีสิ่งอำนวยความสะดวกขั้นสูงจะถูกใช้ในลักษณะที่มีระเบียบวินัยเพื่อจินตนาการถึงโครงสร้างใหม่ (นั่นคือบทเรียนเสียงกระเพื่อม)

ความจริงที่ว่าภาษาที่ไม่มีการพิมพ์แบบสแตติกไม่เคยหมายความว่าโปรแกรมที่เขียนในภาษานั้นจะไม่ได้รับการพิมพ์แบบคงที่ ในทางกลับกันอาจเป็นไปได้ว่าระบบประเภทที่โปรแกรมใช้ยังไม่เป็นทางการเพียงพอสำหรับตัวตรวจสอบชนิดที่มีอยู่ในขณะนี้

มีการพูดคุยในการอ้างอิงหลายอ้างอิงถึงการวิเคราะห์กรณีที่เลวร้ายที่สุด ("ปัญหาการหยุดชะงัก", การแยกวิเคราะห์ PERL) แต่การวิเคราะห์กรณีที่เลวร้ายที่สุดส่วนใหญ่ไม่เกี่ยวข้อง สิ่งที่สำคัญคือสิ่งที่เกิดขึ้นในกรณีส่วนใหญ่หรือในกรณีที่มีประโยชน์ ... อย่างไรก็ตามกำหนดหรือเข้าใจหรือมีประสบการณ์ มาที่นี่อีกเรื่องที่เกี่ยวข้องโดยตรงกับการเพิ่มประสิทธิภาพของโปรแกรม มันเกิดขึ้นนานมาแล้วในมหาวิทยาลัยสำคัญในเท็กซัสระหว่างนักศึกษาปริญญาเอกและที่ปรึกษาของเขา (ซึ่งได้รับการเลือกตั้งในภายหลังในหนึ่งในสถาบันการศึกษาแห่งชาติ) เมื่อฉันจำได้นักเรียนก็ยืนกรานที่จะศึกษาปัญหาการวิเคราะห์ / การปรับให้เหมาะสมซึ่งผู้ให้คำปรึกษาได้แสดงให้เห็นว่าไม่สามารถใช้ได้ ในไม่ช้าพวกเขาก็ไม่ได้พูดคำศัพท์อีกต่อไป แต่นักเรียนถูกต้อง: ปัญหานั้นง่ายในกรณีที่ใช้งานได้จริงที่สุดดังนั้นวิทยานิพนธ์ที่เขาผลิตก็เป็นงานอ้างอิง

และเพื่อแสดงความคิดเห็นเพิ่มเติมเกี่ยวกับคำแถลงว่าPerl parsing is not computableสิ่งที่มีความหมายโดยประโยคนั้นมีปัญหาที่คล้ายกันกับ ML ซึ่งเป็นภาษาที่กรงเล็บที่ดีอย่างน่าทึ่งType checking complexity in ML is a double exponential in the lenght of the program.นั่นเป็นผลลัพธ์ที่แม่นยำและเป็นทางการซึ่งมีความซับซ้อนของกรณีที่เลวร้ายที่สุด ... ซึ่งไม่สำคัญเลย Afaik ผู้ใช้ ML ยังคงรอโปรแกรมเชิงปฏิบัติที่จะระเบิดตัวตรวจสอบชนิด

ในหลายกรณีอย่างที่เคยเป็นมาก่อนเวลาและความสามารถของมนุษย์นั้นน่ากลัวกว่าพลังในการคำนวณ

ปัญหาที่แท้จริงของอนาคตคือการพัฒนาภาษาของเราเพื่อรวมความรู้ใหม่รูปแบบการเขียนโปรแกรมใหม่โดยไม่ต้องเขียนซอฟต์แวร์ดั้งเดิมทั้งหมดที่ยังคงใช้อยู่

ถ้าคุณดูคณิตศาสตร์มันเป็นองค์ความรู้ที่มีขนาดใหญ่มาก ภาษาที่ใช้ในการแสดงความคิดเห็นและแนวคิดได้พัฒนามานานหลายศตวรรษ มันง่ายที่จะเขียนทฤษฎีบทเก่าด้วยแนวคิดใหม่ เราปรับตัวพิสูจน์หลัก แต่ไม่ต้องกังวลกับผลลัพธ์มากมาย

แต่ในกรณีของการเขียนโปรแกรมเราอาจต้องเขียนบทพิสูจน์ใหม่ทั้งหมดตั้งแต่เริ่มต้น (โปรแกรมเป็นบทพิสูจน์) อาจเป็นได้ว่าสิ่งที่เราต้องการจริงๆคือภาษาการเขียนโปรแกรมระดับสูงมากและมีวิวัฒนาการ นักออกแบบเครื่องมือเพิ่มประสิทธิภาพยินดีที่จะติดตาม


0

หมายเหตุสองประการ:

  • ไม่ใช่ภาษาระดับสูงทั้งหมดที่เป็นแบบไดนามิก Haskell อยู่ในระดับสูงมาก แต่ถูกพิมพ์แบบคงที่ทั้งหมด แม้แต่ภาษาโปรแกรมอย่าง Rust, Nim และ D ยังสามารถแสดง abstractions ระดับสูงได้อย่างกระชับและมีประสิทธิภาพ ในความเป็นจริงพวกเขาสามารถกระชับเป็นภาษาแบบไดนามิก

  • มีการคอมไพล์เลอร์ล่วงหน้าสำหรับ optomizing สำหรับภาษาไดนามิกอยู่ การใช้งานเสียงกระเพื่อมที่ดีจะเข้าถึงความเร็วครึ่งหนึ่งของ C

  • การรวบรวม JIT อาจเป็นชัยชนะครั้งใหญ่ที่นี่ Web Application Firewall ของ CloudFlare สร้างรหัส Lua ที่ LuaJIT ดำเนินการ LuaJIT ปรับเส้นทางการเรียกใช้จริงอย่างจริงจัง (โดยทั่วไปคือเส้นทางที่ไม่ใช่การโจมตี) ด้วยผลลัพธ์ที่โค้ดทำงานได้เร็วกว่าโค้ดที่สร้างโดยคอมไพเลอร์สแตติกในปริมาณงานจริง ซึ่งแตกต่างจากคอมไพเลอร์สแตติกที่มีการปรับให้เหมาะสมที่แนะนำโดยโปรไฟล์ LuaJIT จะปรับเปลี่ยนการเปลี่ยนแปลงในพา ธ การประมวลผลที่รันไทม์

  • Deoptimizationก็มีความสำคัญเช่นกัน แทนที่จะเป็นรหัสที่คอมไพล์ด้วย JIT จำเป็นต้องตรวจสอบคลาสที่เป็น monkeypatch การกระทำของ monkeypatching จะทำให้เกิด hook ในระบบรันไทม์ซึ่งจะทิ้งรหัสเครื่องที่ขึ้นอยู่กับนิยามเดิม


นี่เป็นคำตอบอย่างไร กระสุนปืนสามอาจถ้าคุณเพิ่มการอ้างอิง
กราฟิลส์

ฉันสงสัยอย่างมากเกี่ยวกับการอ้างสิทธิ์ว่า PGO ไม่ตรงกับประสิทธิภาพของ LuaJIT สำหรับรหัสแอปพลิเคชันเว็บภายใต้ภาระงานทั่วไป
Konrad Rudolph

@KonradRudolph ข้อได้เปรียบที่สำคัญของ JIT คือ JIT ปรับโค้ดเมื่อเส้นทางที่แตกต่างกลายเป็นร้อน
Demi

@ Demetri ฉันรู้เรื่องนี้ แต่มันยากมากที่จะหาปริมาณว่านี่เป็นข้อได้เปรียบหรือไม่ดูคำตอบของฉัน โดยสรุป: ในขณะที่ JIT สามารถปรับให้เข้ากับการเปลี่ยนแปลงการใช้งาน แต่ยังต้องติดตามสิ่งที่รันไทม์ซึ่งเกิดค่าใช้จ่าย จุดคุ้มทุนสำหรับสิ่งนี้คือสังหรณ์ใจเฉพาะเมื่อมีการเปลี่ยนแปลงพฤติกรรมบ่อยครั้ง สำหรับเว็บแอปอาจมีรูปแบบการใช้งานเพียงอย่างเดียว (หรือน้อยมาก) ที่การปรับให้เหมาะสมจะจ่ายดังนั้นการเพิ่มประสิทธิภาพขั้นต่ำเนื่องจากความสามารถในการปรับตัวไม่ได้ตรงข้ามกับการทำโปรไฟล์อย่างต่อเนื่อง
Konrad Rudolph
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.