ฉันได้พิจารณาใช้Lazy<T>
คุณสมบัติเพื่อช่วยปรับปรุงประสิทธิภาพของรหัสของฉัน (และเรียนรู้เพิ่มเติมเล็กน้อยเกี่ยวกับมัน) ฉันมาที่นี่เพื่อค้นหาคำตอบเกี่ยวกับเวลาที่จะใช้ แต่ดูเหมือนว่าทุกที่ที่ฉันไปมีวลีเช่น:
ใช้การเริ่มต้นแบบขี้เกียจเพื่อเลื่อนการสร้างวัตถุที่มีขนาดใหญ่หรือใช้ทรัพยากรมากหรือการดำเนินการของงานที่ใช้ทรัพยากรมากโดยเฉพาะอย่างยิ่งเมื่อการสร้างหรือการดำเนินการดังกล่าวอาจไม่เกิดขึ้นในช่วงอายุการใช้งานของโปรแกรม
จากMSDN Lazy <T> คลาส
ฉันสับสนเล็กน้อยเพราะฉันไม่แน่ใจว่าจะวาดเส้นตรงไหน ตัวอย่างเช่นฉันคิดว่าการแก้ไขเชิงเส้นเป็นการคำนวณที่ค่อนข้างเร็ว แต่ถ้าฉันไม่จำเป็นต้องทำมันการเริ่มต้นแบบขี้เกียจสามารถช่วยฉันหลีกเลี่ยงการทำมันและมันคุ้มค่าหรือไม่
ในที่สุดฉันก็ตัดสินใจลองทำแบบทดสอบของตัวเองและฉันคิดว่าฉันจะแบ่งปันผลที่นี่ น่าเสียดายที่ฉันไม่ใช่ผู้เชี่ยวชาญในการทำแบบทดสอบเหล่านี้ดังนั้นฉันจึงยินดีรับความคิดเห็นที่แนะนำการปรับปรุง
ลักษณะ
สำหรับกรณีของฉันฉันสนใจเป็นพิเศษเพื่อดูว่า Lazy Properties สามารถช่วยปรับปรุงส่วนของรหัสของฉันที่ทำการแก้ไขจำนวนมาก (ส่วนใหญ่ไม่ได้ใช้งาน) และดังนั้นฉันจึงได้สร้างการทดสอบที่เปรียบเทียบ 3 แนวทาง
ฉันสร้างคลาสการทดสอบแยกต่างหากพร้อมด้วยคุณสมบัติการทดสอบ 20 รายการ (ให้เรียกว่าคุณสมบัติที) สำหรับแต่ละวิธี
- คลาส GetInterp: ทำการแก้ไขเชิงเส้นทุกครั้งที่มีคุณสมบัติ t
- คลาส InitInterp:เริ่มต้นคุณสมบัติ t โดยเรียกใช้การแก้ไขเชิงเส้นสำหรับแต่ละรายการในตัวสร้าง รับเพียงแค่ส่งกลับสองครั้ง
- InitLazy Class:ตั้งค่าคุณสมบัติ t- เป็นคุณสมบัติ Lazy เพื่อให้การแก้ไขเชิงเส้นทำงานครั้งเดียวเมื่อคุณสมบัติได้รับครั้งแรก การได้รับครั้งต่อมาควรจะคืนค่า double ที่คำนวณแล้ว
ผลการทดสอบวัดเป็นมิลลิวินาทีและมีค่าเฉลี่ย 50 อินสแตนซ์หรือ 20 คุณสมบัติที่ได้รับ การทดสอบแต่ละครั้งจะทำงาน 5 ครั้ง
ทดสอบผลลัพธ์ 1:อินสแตนซ์ (เฉลี่ย 50 instantiations)
Class 1 2 3 4 5 Avg %
------------------------------------------------------------------------
GetInterp 0.005668 0.005722 0.006704 0.006652 0.005572 0.0060636 6.72
InitInterp 0.08481 0.084908 0.099328 0.098626 0.083774 0.0902892 100.00
InitLazy 0.058436 0.05891 0.068046 0.068108 0.060648 0.0628296 69.59
ทดสอบผลลัพธ์ 2: รับครั้งแรก (โดยเฉลี่ย 20 คุณสมบัติได้รับ)
Class 1 2 3 4 5 Avg %
------------------------------------------------------------------------
GetInterp 0.263 0.268725 0.31373 0.263745 0.279675 0.277775 54.38
InitInterp 0.16316 0.161845 0.18675 0.163535 0.173625 0.169783 33.24
InitLazy 0.46932 0.55299 0.54726 0.47878 0.505635 0.510797 100.00
ทดสอบ 3 ผลลัพธ์: รับครั้งที่สอง (โดยเฉลี่ย 20 คุณสมบัติได้รับ)
Class 1 2 3 4 5 Avg %
------------------------------------------------------------------------
GetInterp 0.08184 0.129325 0.112035 0.097575 0.098695 0.103894 85.30
InitInterp 0.102755 0.128865 0.111335 0.10137 0.106045 0.110074 90.37
InitLazy 0.19603 0.105715 0.107975 0.10034 0.098935 0.121799 100.00
ข้อสังเกต
GetInterp
เร็วที่สุดในการยกตัวอย่างตามที่คาดไว้เพราะมันไม่ได้ทำอะไรเลย InitLazy
เร็วกว่า instantiate กว่าInitInterp
แนะนำว่าค่าใช้จ่ายในการตั้งค่าคุณสมบัติขี้เกียจนั้นเร็วกว่าการคำนวณการแก้ไขเชิงเส้น อย่างไรก็ตามฉันสับสนเล็กน้อยที่นี่เพราะInitInterp
ควรทำการประมาณ 20 เชิงเส้น (เพื่อตั้งค่าเป็นคุณสมบัติ t) แต่ใช้เวลาเพียง 0.09 ms ในการสร้างอินสแตนซ์ (ทดสอบ 1) เมื่อเทียบกับGetInterp
ที่ใช้เวลา 0.28 มิลลิวินาทีในการแก้ไขเชิงเส้นเดียว ครั้งแรก (ทดสอบ 2) และ 0.1 ms เพื่อทำครั้งที่สอง (ทดสอบ 3)
ใช้InitLazy
เวลานานกว่า 2 เท่าGetInterp
ในการรับคุณสมบัติเป็นครั้งแรกในขณะInitInterp
ที่เร็วที่สุดเนื่องจากมีคุณสมบัติในระหว่างการสร้างอินสแตนซ์ (อย่างน้อยนั่นคือสิ่งที่ควรทำ แต่ทำไมผลของอินสแตนซ์นั้นเร็วกว่าการสอดแทรกเชิงเส้นเดี่ยวมาก?
น่าเสียดายที่ดูเหมือนว่ามีการเพิ่มประสิทธิภาพโค้ดอัตโนมัติในการทดสอบของฉัน ควรใช้เวลาGetInterp
เดียวกันเพื่อให้ได้ทรัพย์สินในครั้งแรกเหมือนครั้งที่สอง แต่จะแสดงเร็วกว่า 2x ดูเหมือนว่าการเพิ่มประสิทธิภาพนี้จะมีผลกับคลาสอื่นด้วยเช่นกันเนื่องจากพวกเขาทั้งหมดใช้เวลาในการทดสอบ 3 เท่ากันอย่างไรก็ตามการปรับให้เหมาะสมดังกล่าวอาจเกิดขึ้นในรหัสการผลิตของตัวเองซึ่งอาจเป็นข้อพิจารณาที่สำคัญ
สรุปผลการวิจัย
ในขณะที่ผลลัพธ์บางอย่างเป็นไปตามคาด แต่ก็มีผลลัพธ์ที่ไม่คาดคิดที่น่าสนใจมากซึ่งอาจเกิดจากการปรับโค้ดให้เหมาะสม แม้แต่คลาสที่ดูเหมือนว่าพวกเขากำลังทำงานเป็นจำนวนมากในคอนสตรัคเตอร์ผลลัพธ์ของอินสแตนซ์แสดงว่าพวกเขายังคงสามารถสร้างได้อย่างรวดเร็วเมื่อเทียบกับการได้รับคุณสมบัติสองชั้น ในขณะที่ผู้เชี่ยวชาญในสาขานี้อาจสามารถแสดงความคิดเห็นและตรวจสอบได้อย่างละเอียดยิ่งขึ้นความรู้สึกส่วนตัวของฉันคือฉันต้องทำการทดสอบนี้อีกครั้ง แต่ในรหัสการผลิตของฉันเพื่อตรวจสอบว่ามีการเพิ่มประสิทธิภาพประเภทใดบ้าง อย่างไรก็ตามฉันคาดหวังว่าInitInterp
อาจเป็นวิธีที่จะไป
get { if (foo == null) foo = new Foo(); return foo; }
. และมีสถานที่ที่เป็นไปได้มากมายที่จะใช้ ...