ไม่มีใครรู้คำตอบและ / หรือมีความคิดเห็นเกี่ยวกับเรื่องนี้?
เนื่องจากโดยปกติสิ่งทอจะมีขนาดไม่ใหญ่มากฉันจึงคิดว่าการใช้โครงสร้างจะเหมาะสมกว่าคลาสสำหรับสิ่งเหล่านี้ คุณพูดอะไร?
ไม่มีใครรู้คำตอบและ / หรือมีความคิดเห็นเกี่ยวกับเรื่องนี้?
เนื่องจากโดยปกติสิ่งทอจะมีขนาดไม่ใหญ่มากฉันจึงคิดว่าการใช้โครงสร้างจะเหมาะสมกว่าคลาสสำหรับสิ่งเหล่านี้ คุณพูดอะไร?
คำตอบ:
Microsoft สร้างประเภทการอ้างอิงทุกประเภททูเปิลเพื่อความเรียบง่าย
โดยส่วนตัวฉันคิดว่านี่เป็นความผิดพลาด Tuples ที่มีมากกว่า 4 ช่องนั้นผิดปกติมากและควรแทนที่ด้วยทางเลือกที่หลากหลายกว่าอยู่ดี (เช่นประเภทระเบียนใน F #) ดังนั้นจึงมีเพียงสิ่งเล็ก ๆ ที่น่าสนใจเท่านั้น การวัดประสิทธิภาพของฉันเองแสดงให้เห็นว่าสิ่งที่ไม่ได้บรรจุกล่องที่มีขนาดสูงสุด 512 ไบต์ยังคงเร็วกว่าสิ่งที่เป็นกล่อง
แม้ว่าประสิทธิภาพของหน่วยความจำจะเป็นเรื่องที่น่ากังวล แต่ฉันเชื่อว่าปัญหาที่สำคัญคือค่าใช้จ่ายของตัวรวบรวมขยะ. NET การจัดสรรและการรวบรวมมีราคาแพงมากบน. NET เนื่องจากตัวรวบรวมขยะไม่ได้รับการปรับให้เหมาะสมมากนัก (เช่นเมื่อเทียบกับ JVM) ยิ่งไปกว่านั้น. NET GC (เวิร์กสเตชัน) เริ่มต้นยังไม่ได้รับการขนาน ดังนั้นโปรแกรมคู่ขนานที่ใช้ทูเปิลจึงหยุดชะงักเนื่องจากคอร์ทั้งหมดต่อสู้เพื่อตัวรวบรวมขยะที่ใช้ร่วมกันทำลายความสามารถในการปรับขนาด นี่ไม่ใช่แค่ความกังวลที่สำคัญ แต่ AFAIK ถูกไมโครซอฟท์ละเลยอย่างสิ้นเชิงเมื่อตรวจสอบปัญหานี้
ข้อกังวลอีกประการหนึ่งคือการจัดส่งเสมือน ประเภทการอ้างอิงสนับสนุนประเภทย่อยดังนั้นโดยทั่วไปสมาชิกของพวกเขาจะถูกเรียกใช้ผ่านการจัดส่งเสมือน ในทางตรงกันข้ามประเภทค่าไม่สามารถรองรับชนิดย่อยได้ดังนั้นการเรียกสมาชิกจึงไม่คลุมเครือและสามารถดำเนินการเป็นการเรียกฟังก์ชันโดยตรงได้เสมอ การจัดส่งเสมือนมีราคาแพงมากสำหรับฮาร์ดแวร์สมัยใหม่เนื่องจาก CPU ไม่สามารถคาดเดาได้ว่าตัวนับโปรแกรมจะสิ้นสุดที่ใด JVM มีความยาวมากในการปรับการจัดส่งเสมือนให้เหมาะสม แต่. NET ไม่ทำ อย่างไรก็ตาม. NET มีการหลีกเลี่ยงจากการจัดส่งเสมือนในรูปแบบของชนิดค่า ดังนั้นการแสดง tuples เป็นประเภทค่าจึงสามารถปรับปรุงประสิทธิภาพที่นี่ได้อย่างมาก ตัวอย่างเช่นการโทรGetHashCode
บน 2-tuple หนึ่งล้านครั้งใช้เวลา 0.17 วินาที แต่การเรียกมันบนโครงสร้างที่เทียบเท่าจะใช้เวลาเพียง 0.008 วินาทีนั่นคือชนิดของค่านั้นเร็วกว่าชนิดอ้างอิงถึง 20 เท่า
สถานการณ์จริงที่มักเกิดปัญหาด้านประสิทธิภาพกับสิ่งเหล่านี้ขึ้นอยู่กับการใช้ทูเปิลเป็นคีย์ในพจนานุกรม ฉันสะดุดกับเธรดนี้จริงๆโดยไปตามลิงค์จากคำถาม Stack Overflow F # เรียกใช้อัลกอริทึมของฉันช้ากว่า Python! โดยที่โปรแกรม F # ของผู้เขียนช้ากว่า Python ของเขาอย่างแม่นยำเพราะเขาใช้ tuples แบบบรรจุกล่อง การแกะกล่องด้วยตนเองโดยใช้struct
ประเภทที่เขียนด้วยมือทำให้โปรแกรม F # ของเขาเร็วขึ้นหลายเท่าและเร็วกว่า Python ปัญหาเหล่านี้จะไม่เกิดขึ้นหากสิ่งที่เพิ่มขึ้นแสดงด้วยประเภทค่าและไม่ใช่ประเภทอ้างอิงที่ขึ้นต้นด้วย ...
Tuple<_,...,_>
ประเภทอาจถูกปิดผนึกซึ่งในกรณีนี้ไม่จำเป็นต้องใช้การจัดส่งเสมือนแม้ว่าจะเป็นประเภทอ้างอิงก็ตาม ฉันสงสัยมากว่าทำไมพวกเขาถึงไม่ปิดผนึกมากกว่าทำไมถึงเป็นประเภทอ้างอิง
สาเหตุส่วนใหญ่น่าจะเป็นเพราะสิ่งที่มีขนาดเล็กเท่านั้นที่จะเหมาะสมกับประเภทของค่าเนื่องจากจะมีหน่วยความจำขนาดเล็ก สิ่งที่มีขนาดใหญ่กว่า (เช่นสิ่งที่มีคุณสมบัติมากกว่า) จะได้รับผลกระทบจากประสิทธิภาพเนื่องจากมีขนาดใหญ่กว่า 16 ไบต์
แทนที่จะให้สิ่งสองสิ่งบางอย่างเป็นประเภทค่าและอื่น ๆ เป็นประเภทอ้างอิงและบังคับให้นักพัฒนาทราบว่าสิ่งใดที่ฉันคิดว่าคนที่ Microsoft คิดว่าทำให้ประเภทการอ้างอิงทั้งหมดนั้นง่ายกว่า
อ๊ะสงสัยคอนเฟิร์ม! โปรดดูBuilding Tuple :
การตัดสินใจที่สำคัญประการแรกคือว่าจะปฏิบัติต่อสิ่งที่เป็นสิ่งอ้างอิงหรือประเภทค่า เนื่องจากไม่เปลี่ยนรูปเมื่อใดก็ตามที่คุณต้องการเปลี่ยนค่าของทูเปิลคุณจึงต้องสร้างใหม่ หากเป็นประเภทการอ้างอิงหมายความว่าอาจมีขยะจำนวนมากที่สร้างขึ้นหากคุณกำลังเปลี่ยนองค์ประกอบในทูเพิลแบบวนซ้ำ F # tuples เป็นประเภทอ้างอิง แต่มีความรู้สึกจากทีมงานว่าพวกเขาสามารถรับรู้ถึงการปรับปรุงประสิทธิภาพได้ถ้าสิ่งที่สองและสามอย่างอาจเป็นประเภทค่าแทน บางทีมที่สร้างสิ่งทอภายในได้ใช้ค่าแทนชนิดการอ้างอิงเนื่องจากสถานการณ์ของพวกเขามีความอ่อนไหวมากในการสร้างวัตถุที่มีการจัดการจำนวนมาก พวกเขาพบว่าการใช้ประเภทค่าทำให้ประสิทธิภาพดีขึ้น ในร่างข้อกำหนด tuple ฉบับร่างแรกของเรา เราเก็บสิ่งที่สองสามและสี่องค์ประกอบไว้เป็นประเภทค่าโดยส่วนที่เหลือเป็นประเภทอ้างอิง อย่างไรก็ตามในระหว่างการประชุมการออกแบบที่มีตัวแทนจากภาษาอื่นมีการตัดสินใจว่าการออกแบบ "แยก" นี้จะทำให้สับสนเนื่องจากความหมายที่แตกต่างกันเล็กน้อยระหว่างสองประเภท ความสม่ำเสมอในพฤติกรรมและการออกแบบถูกกำหนดให้มีความสำคัญสูงกว่าการเพิ่มประสิทธิภาพที่อาจเกิดขึ้น จากข้อมูลที่ป้อนนี้เราได้เปลี่ยนการออกแบบเพื่อให้สิ่งที่เพิ่มขึ้นทั้งหมดเป็นประเภทอ้างอิงแม้ว่าเราจะขอให้ทีม F # ทำการตรวจสอบประสิทธิภาพบางอย่างเพื่อดูว่ามีการเร่งความเร็วเมื่อใช้ประเภทค่าสำหรับสิ่งทอบางขนาดหรือไม่ มีวิธีที่ดีในการทดสอบสิ่งนี้เนื่องจากคอมไพเลอร์เขียนด้วย F # เป็นตัวอย่างที่ดีของโปรแกรมขนาดใหญ่ที่ใช้ tuples ในหลากหลายสถานการณ์ ในท้ายที่สุดทีม F # พบว่าไม่ได้รับการปรับปรุงประสิทธิภาพเมื่อสิ่งสองสิ่งบางอย่างเป็นประเภทค่าแทนประเภทอ้างอิง สิ่งนี้ทำให้เรารู้สึกดีขึ้นเกี่ยวกับการตัดสินใจใช้ประเภทอ้างอิงสำหรับทูเพิล
ถ้าชนิด. NET System.Tuple <... >ถูกกำหนดให้เป็นโครงสร้างก็จะไม่สามารถปรับขนาดได้ ตัวอย่างเช่น ternary tuple ของจำนวนเต็มยาวในปัจจุบันมีขนาดดังนี้:
type Tuple3 = System.Tuple<int64, int64, int64>
type Tuple33 = System.Tuple<Tuple3, Tuple3, Tuple3>
sizeof<Tuple3> // Gets 4
sizeof<Tuple33> // Gets 4
หาก ternary tuple ถูกกำหนดให้เป็นโครงสร้างผลลัพธ์จะเป็นดังนี้ (ตามตัวอย่างการทดสอบที่ฉันใช้):
sizeof<Tuple3> // Would get 32
sizeof<Tuple33> // Would get 104
เนื่องจาก tuples มีการสนับสนุนไวยากรณ์ในตัวใน F # และมักใช้ในภาษานี้สิ่งที่เรียกว่า "struct" จึงทำให้โปรแกรมเมอร์ F # มีความเสี่ยงที่จะเขียนโปรแกรมที่ไม่มีประสิทธิภาพโดยที่ไม่รู้ตัวด้วยซ้ำ มันจะเกิดขึ้นอย่างง่ายดาย:
let t3 = 1L, 2L, 3L
let t33 = t3, t3, t3
ในความคิดของฉันสิ่งที่เป็น "โครงสร้าง" จะทำให้เกิดความเป็นไปได้สูงที่จะสร้างความไร้ประสิทธิภาพอย่างมีนัยสำคัญในการเขียนโปรแกรมในชีวิตประจำวัน ในทางกลับกันทูเพิล "คลาส" ที่มีอยู่ในปัจจุบันยังทำให้เกิดความไร้ประสิทธิภาพบางอย่างดังที่ @Jon กล่าวไว้ อย่างไรก็ตามฉันคิดว่าผลคูณของ "ความน่าจะเป็นในการเกิด" ครั้ง "ความเสียหายที่อาจเกิดขึ้น" จะสูงกว่าโครงสร้างที่เป็นอยู่ในปัจจุบันมาก ดังนั้นการดำเนินการในปัจจุบันจึงเป็นสิ่งที่ชั่วร้ายน้อยกว่า
ตามหลักการแล้วจะมีสิ่งทอทั้งแบบ "คลาส" และ "โครงสร้าง" ทั้งสองแบบที่รองรับวากยสัมพันธ์ใน F #!
แก้ไข (2017-10-07)
ตอนนี้สิ่งที่เป็นโครงสร้างได้รับการสนับสนุนอย่างเต็มที่ดังนี้:
ref
หรืออาจไม่ชอบความจริงที่เรียกว่า "โครงสร้างที่ไม่เปลี่ยนรูป" ไม่ได้โดยเฉพาะอย่างยิ่งเมื่ออยู่ในกล่อง มันแย่เกินไป. net ไม่เคยใช้แนวคิดการส่งผ่านพารามิเตอร์โดยบังคับconst ref
เนื่องจากในหลาย ๆ กรณีความหมายเช่นนี้เป็นสิ่งที่จำเป็นจริงๆ
Dictionary
เช่นที่นี่: stackoverflow.com/questions/5850243 / …
สำหรับ 2-tuples คุณยังคงสามารถใช้ KeyValuePair <TKey, TValue> จาก Common Type System เวอร์ชันก่อนหน้าได้เสมอ เป็นประเภทมูลค่า
การชี้แจงเล็กน้อยสำหรับบทความของ Matt Ellis ก็คือความแตกต่างในการใช้ความหมายระหว่างประเภทการอ้างอิงและประเภทของค่านั้นเป็นเพียง "เล็กน้อย" เมื่อความไม่เปลี่ยนรูปมีผล (ซึ่งแน่นอนว่าจะเป็นเช่นนั้นในที่นี้) อย่างไรก็ตามฉันคิดว่ามันน่าจะดีที่สุดในการออกแบบ BCL ที่จะไม่ทำให้เกิดความสับสนในการให้ Tuple ข้ามไปยังประเภทการอ้างอิงในบางเกณฑ์
ฉันไม่รู้ แต่คุณเคยใช้ F # Tuples เป็นส่วนหนึ่งของภาษาหรือไม่ ถ้าฉันสร้าง. dll และส่งคืน Tuples ประเภทหนึ่งก็คงจะดีถ้ามีประเภทที่จะใส่เข้าไปฉันสงสัยว่าตอนนี้ F # เป็นส่วนหนึ่งของภาษา (.Net 4) มีการปรับเปลี่ยนบางอย่างกับ CLR เพื่อรองรับโครงสร้างทั่วไปบางอย่าง ใน F #
จากhttp://en.wikibooks.org/wiki/F_Sharp_Programming/Tuples_and_Records
let scalarMultiply (s : float) (a, b, c) = (a * s, b * s, c * s);;
val scalarMultiply : float -> float * float * float -> float * float * float
scalarMultiply 5.0 (6.0, 10.0, 20.0);;
val it : float * float * float = (30.0, 50.0, 100.0)
ValueTuple<...>
มีครอบครัวประเภท ดูข้อมูลอ้างอิงที่ C # tuple types