ภาษา OO สมัยใหม่สามารถแข่งขันกับประสิทธิภาพการจัดเก็บอาร์เรย์ของ C ++ ได้หรือไม่


40

ฉันเพิ่งสังเกตเห็นว่าภาษาการเขียนโปรแกรม OO สมัยใหม่ทุกอย่างที่ฉันคุ้นเคยอย่างน้อยก็มี (ซึ่งโดยพื้นฐานแล้วก็คือ Java, C # และ D) ช่วยให้อาร์เรย์ covariant นั่นคืออาร์เรย์สตริงเป็นอาร์เรย์วัตถุ:

Object[] arr = new String[2];   // Java, C# and D allow this

อาร์เรย์ของ Covariant เป็นรูในระบบแบบสแตติก พวกเขาทำให้เกิดข้อผิดพลาดประเภทที่เป็นไปได้ที่ไม่สามารถตรวจพบได้ในเวลารวบรวมดังนั้นทุกการเขียนไปยังอาเรย์ต้องถูกตรวจสอบที่รันไทม์:

arr[0] = "hello";        // ok
arr[1] = new Object();   // ArrayStoreException

ดูเหมือนว่าจะมีประสิทธิภาพที่แย่มากถ้าฉันทำร้านค้ามากมาย

C ++ ไม่มีอาร์เรย์ที่แปรปรวนร่วมดังนั้นจึงไม่จำเป็นต้องทำการตรวจสอบรันไทม์อีกต่อไปซึ่งหมายความว่าไม่มีการลงโทษประสิทธิภาพ

มีการวิเคราะห์เพื่อลดจำนวนการตรวจสอบรันไทม์ที่จำเป็นหรือไม่? ตัวอย่างเช่นถ้าฉันพูดว่า:

arr[1] = arr[0];

ใครจะยืนยันว่าร้านค้าไม่อาจล้มเหลว ฉันแน่ใจว่ามีการเพิ่มประสิทธิภาพที่เป็นไปได้อื่น ๆ อีกมากมายที่ฉันไม่ได้คิด

คอมไพเลอร์สมัยใหม่ทำการปรับแต่งเหล่านี้จริง ๆ หรือไม่หรือว่าฉันต้องใช้ชีวิตอยู่กับความจริงที่ว่าตัวอย่างเช่น Quicksort O (n log n) การตรวจสอบรันไทม์ที่ไม่จำเป็นต้องทำเสมอหรือไม่?

ภาษา OO สมัยใหม่สามารถหลีกเลี่ยงค่าโสหุ้ยที่สร้างขึ้นได้โดยการสนับสนุนอาร์เรย์ตัวแปรร่วม


7
ฉันสับสนว่าทำไมคุณแนะนำ C ++ เร็วกว่าภาษาอื่น ๆ ในคุณลักษณะ C ++ ไม่สนับสนุน

17
@eco: C ++ เร็วขึ้นด้วยการเข้าถึงอาร์เรย์เนื่องจากไม่รองรับอาร์เรย์ร่วม Fred ต้องการทราบว่าเป็นไปได้หรือไม่ที่ "ภาษา OO สมัยใหม่" จะช่วยลดค่าใช้จ่ายของอาร์เรย์ที่แปรปรวนร่วมเพื่อให้เข้าใกล้ความเร็วของ C ++ มากขึ้น
Mooing Duck

13
"รหัสที่คอมไพล์ แต่มีข้อยกเว้นในช่วงรันไทม์เป็นข่าวร้าย"

4
@Jesse และผู้คนนับล้านเขียนรหัสที่เชื่อถือได้และปรับขนาดได้สูงในภาษาแบบไดนามิก Imo: ถ้าคุณไม่เขียนกรณีทดสอบสำหรับรหัสของคุณฉันไม่สนใจว่ามีข้อผิดพลาดของคอมไพเลอร์หรือไม่ฉันจะไม่ไว้ใจมันอย่างไรก็ตาม
Voo

7
@Jesse และเมื่อไรที่คุณคาดหวังว่าจะมีข้อยกเว้น แต่เมื่อถึงรันไทม์ ปัญหาไม่ใช่รหัสที่ส่งข้อยกเว้นตอนรันไทม์ - มีหลายกรณีที่เหมาะสมดี - ปัญหาคือรหัสที่รับประกันว่าผิดซึ่งไม่ได้รับการตรวจจับโดยคอมไพเลอร์ แต่กลับส่งผลให้เกิดข้อยกเว้นที่ รันไทม์
Jonathan M Davis

คำตอบ:


33

D ไม่มีอาร์เรย์ที่แปรปรวนร่วม มันอนุญาตให้พวกเขาก่อนที่จะปล่อยล่าสุด ( dmd 2.057 ) แต่ข้อผิดพลาดที่ได้รับการแก้ไข

อาร์เรย์ใน D มีประสิทธิภาพเพียงโครงสร้างที่มีตัวชี้และความยาว:

struct A(T)
{
    T* ptr;
    size_t length;
}

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


ไม่ปรากฏ - d-programming-language.org/arrays.htmlกล่าวว่า "อาเรย์แบบคงที่T[dim]สามารถแปลงเป็นหนึ่งในรายการต่อไปนี้โดยปริยาย: ... U[]... อาเรย์แบบไดนามิกT[]สามารถแปลงเป็นหนึ่งในรายการต่อไปนี้โดยปริยาย: U[]. .. Uชั้นฐานTอยู่ที่ไหน "
Ben Voigt

2
@BenVoigt ดังนั้นเอกสารออนไลน์ต้องได้รับการอัปเดต พวกเขาไม่ได้อัปเดตเสมอไป 100% การแปลงจะทำงานได้const U[]ตั้งแต่นั้นคุณไม่สามารถกำหนดประเภทที่ไม่ถูกต้องให้กับองค์ประกอบของอาร์เรย์ได้ แต่T[]จะไม่แปลงU[]เป็นตราบเท่าที่U[]ไม่แน่นอน การอนุญาตให้อาร์เรย์ covariant เหมือนที่เคยทำมาเป็นข้อบกพร่องการออกแบบที่จริงจังซึ่งขณะนี้ได้รับการแก้ไขแล้ว
Jonathan M Davis

@JonathanMDavis: อาร์เรย์ของ Covariant นั้นดูดี แต่ใช้งานได้ดีกับสถานการณ์เฉพาะของรหัสซึ่งจะเขียนไปยังองค์ประกอบของอาร์เรย์ที่อ่านจากอาร์เรย์เดียวกันนั้นเท่านั้น D จะอนุญาตให้หนึ่งเขียนวิธีที่สามารถจัดเรียงอาร์เรย์ของประเภทใด ๆ ได้อย่างไร?
supercat

@supercat ถ้าคุณต้องการที่จะเขียนฟังก์ชั่นที่จะจัดเรียงตามประเภทของมันเองแล้วทำการ templatize เช่นdlang.org/phobos/std_algorithm.html#sort
Jonathan M Davis

21

ใช่การเพิ่มประสิทธิภาพที่สำคัญอย่างหนึ่งคือ:

sealed class Foo
{
}

ใน C # คลาสนี้ไม่สามารถเป็น supertype สำหรับประเภทใดก็ได้ดังนั้นคุณสามารถหลีกเลี่ยงการตรวจสอบประเภทของอาร์เรย์Fooได้

และสำหรับคำถามที่สองในอาร์เรย์ # F ไม่สามารถใช้ร่วมกันได้ (แต่ฉันเดาว่าการตรวจสอบจะยังคงอยู่ใน CLR เว้นแต่จะพบว่าไม่จำเป็นในการปรับให้เหมาะสมที่รันไทม์)

let a = [| "st" |]
let b : System.Object[] = a // Fails

https://stackoverflow.com/questions/7339013/array-covariance-in-f

ปัญหาที่ค่อนข้างเกี่ยวข้องคือการตรวจสอบขอบเขตของอาเรย์ นี่อาจเป็นสิ่งที่น่าสนใจ (แต่เก่า) อ่านเกี่ยวกับการปรับให้เหมาะสมที่ทำใน CLR (ความแปรปรวนร่วมถูกกล่าวถึงด้วย 1 ที่): http://blogs.msdn.com/b/clrcodegeneration/archive/2009/08/13/array-bounds -Check-กำจัด-in-the-clr.aspx


2
สกาล่ายังป้องกันโครงสร้างนี้: val a = Array("st"); val b: Array[Any] = aเป็นสิ่งผิดกฎหมาย (อย่างไรก็ตามอาร์เรย์ใน Scala คือ ... เวทมนตร์พิเศษ ... เนื่องจาก JVM ต้นแบบใช้แล้ว)
pst

13

คำตอบ Java:

ฉันคิดว่าคุณยังไม่ได้ทำการเปรียบเทียบรหัสจริงใช่ไหม? โดยทั่วไป 90% ของการร่ายแบบไดนามิกทั้งหมดใน Java นั้นฟรีเพราะ JIT สามารถกำจัดพวกมันได้ (quicksort น่าจะเป็นตัวอย่างที่ดีสำหรับเรื่องนี้) และส่วนที่เหลือเป็นld/cmp/brลำดับที่คาดเดาได้อย่างแน่นอน (ถ้าไม่เช่นนั้น ข้อยกเว้นการส่งแบบไดนามิกทั้งหมดเหล่านั้นหรือไม่)

เราทำการโหลดเร็วกว่าการเปรียบเทียบจริงสาขาจะทำนายได้อย่างถูกต้องใน 99.9999% (คิดเป็นสถิติ!) ของทุกกรณีดังนั้นเราจึงไม่ถ่วงท่อ (สมมติว่าเราไม่ได้โหลดหน่วยความจำด้วยถ้าหาก ไม่ดีที่จะเห็นได้ชัด แต่ก็จำเป็นต้องโหลด) ดังนั้นค่าใช้จ่ายคือ 1 รอบนาฬิกาหาก JIT ไม่สามารถหลีกเลี่ยงการตรวจสอบได้เลย

ค่าใช้จ่ายบางอย่าง? แน่นอน แต่ฉันสงสัยว่าคุณจะสังเกตเห็นมัน ..


เพื่อช่วยสนับสนุนคำตอบของฉันโปรดดูดร. คลิฟ Click blogpost ที่พูดถึงประสิทธิภาพของ Java vs. C


10

D ไม่อนุญาตให้มีอาร์เรย์ covariant

void main()
{
    class Foo {}
    Object[] a = new Foo[10];
}  

/* Error: cannot implicitly convert expression (new Foo[](10LU)) of type Foo[]
to Object[] */

อย่างที่คุณพูดมันจะเป็นรูในระบบประเภทที่อนุญาตสิ่งนี้

คุณสามารถได้รับการอภัยสำหรับข้อผิดพลาดเนื่องจากข้อผิดพลาดนี้เพิ่งได้รับการแก้ไขใน DMD ล่าสุดที่เผยแพร่เมื่อวันที่ 13 ธันวาคม

การเข้าถึง Array ใน D นั้นเร็วเท่ากับ C หรือ C ++


ตามที่d-programming-language.org/arrays.html "สแตติกอาเรย์ T [สลัว] สามารถถูกแปลงเป็นหนึ่งในรายการต่อไปนี้: ... U [] ... อาเรย์ไดนามิก T [] สามารถถูกแปลงโดยปริยาย ถึงหนึ่งในสิ่งต่อไปนี้: U [] ... โดยที่ U เป็นคลาสพื้นฐานของ T "
Ben Voigt

1
@BenVoigt: เอกสารที่ล้าสมัย
BCS

1
@BenVoigt: ฉันได้สร้างคำขอดึงเพื่ออัปเดตเอกสาร หวังว่าจะมีการแก้ไขในไม่ช้า ขอบคุณที่ชี้นำ
ปีเตอร์อเล็กซานเดอร์

5

จากการทดสอบที่ฉันทำบนแล็ปท็อปราคาถูกความแตกต่างระหว่างการใช้งานint[]และInteger[]ประมาณ 1.0 ns ความแตกต่างน่าจะเกิดจากการตรวจสอบพิเศษสำหรับประเภท

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

การเปรียบเทียบเพื่อโทรมีแนวโน้มที่จะมีราคาแพงกว่ามากโดยเฉพาะถ้าคุณใช้วัตถุที่ซับซ้อนเช่นสตริง


2

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

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

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


1

หรือฉันต้องอยู่กับความจริงที่ว่าตัวอย่าง Quicksort จะทำการตรวจสอบรันไทม์ที่ไม่จำเป็นของ O (n log n) เสมอหรือไม่

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

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

ดังนั้นใช่อยู่กับความจริงที่ Quicksort ทำการตรวจสอบปลอม O (n log n) และเพิ่มประสิทธิภาพหลังจากทำโปรไฟล์


1

Scala เป็นภาษา OO ที่มีค่าคงที่มากกว่าอาร์เรย์ covariant เป็นเป้าหมายของ JVM ดังนั้นจึงไม่มีประสิทธิภาพชนะ แต่หลีกเลี่ยงความผิดพลาดทั่วไปสำหรับทั้ง Java และ C # ที่ลดทอนความปลอดภัยประเภทของพวกเขาด้วยเหตุผลด้านความเข้ากันได้แบบย้อนหลัง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.