ประสิทธิภาพของวิธีการแบบคงที่เทียบกับวิธีการของอินสแตนซ์


109

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

พิจารณา:

public sealed class InstanceClass
{
      public int DoOperation1(string input)
      {
          // Some operation.
      }

      public int DoOperation2(string input)
      {
          // Some operation.
      }

      // … more instance methods.
}

public static class StaticClass
{
      public static int DoOperation1(string input)
      {
          // Some operation.
      }

      public static int DoOperation2(string input)
      {
          // Some operation.
      }

      // … more static methods.
}

ชั้นเรียนข้างต้นแสดงถึงรูปแบบสไตล์ผู้ช่วย

ในคลาสอินสแตนซ์การแก้ไขวิธีการอินสแตนซ์จะใช้เวลาสักครู่เพื่อต่อต้าน StaticClass

คำถามของฉันคือ:

  1. เมื่อการรักษาสถานะไม่เป็นปัญหา (ไม่จำเป็นต้องมีฟิลด์หรือคุณสมบัติ) การใช้คลาสคงที่จะดีกว่าเสมอไปหรือไม่?

  2. ในกรณีที่มีนิยามคลาสแบบคงที่เหล่านี้จำนวนมาก (เช่น 100 ซึ่งมีวิธีการคงที่หลายวิธี) สิ่งนี้จะส่งผลต่อประสิทธิภาพการดำเนินการหรือการใช้หน่วยความจำในเชิงลบเมื่อเทียบกับนิยามคลาสอินสแตนซ์จำนวนเดียวกันหรือไม่

  3. เมื่อมีการเรียกวิธีอื่นภายในคลาสอินสแตนซ์เดียวกันการแก้ปัญหาอินสแตนซ์ยังคงเกิดขึ้นหรือไม่ ตัวอย่างเช่นการใช้คีย์เวิร์ด [this] เช่นthis.DoOperation2("abc")จากภายในDoOperation1อินสแตนซ์เดียวกัน



"ความละเอียดอินสแตนซ์" หมายความว่าอย่างไร ในระดับ IL ตัวชี้ "นี้" จะพร้อมใช้งานเช่นเดียวกับตัวแปรโลคัลอื่น ๆ ในความเป็นจริงใน CLR / JIT เวอร์ชันเก่าคุณสามารถเรียกอินสแตนซ์ - เมธอดบน NULL ได้โดยที่มันไม่ได้แตะ 'this' - โค้ดเพิ่งบินผ่านและล้มเหลวโดยไม่มีอะไรเลย .. ตอนนี้ CLR / JIT มี null อย่างชัดเจน - ตรวจสอบสมาชิกทุกคนวิงวอน ..
quetzalcoatl

> vijaymukhi.com/documents/books/ilbook/chap8.htmและ 'call instance' เทียบกับ 'call' อดีตคาดว่าพารามิเตอร์ "this" และตัวหลัง - ไม่
quetzalcoatl

@Quetzalcoatl ขออภัยในความสับสนคำถามนี้เป็นวิธีการเพิ่มเติมจากอินสแตนซ์เดียวกันและหากต้องการให้อินสแตนซ์ได้รับการแก้ไขด้วยตัวเอง
Bernie White

1
@quetzalcoatl ฉันคิดว่าเขาหมายถึง "คอมไพเลอร์กำจัดการตรวจสอบที่thisชี้ไปยังบางสิ่งเมื่อคลาสเรียกใช้วิธีการอินสแตนซ์ในตัวเอง"
Jon Hanna

คำตอบ:


153

ตามทฤษฎีแล้ววิธีการแบบคงที่ควรทำงานได้ดีกว่าวิธีอินสแตนซ์เล็กน้อยสิ่งอื่น ๆ ทั้งหมดเท่ากันเนื่องจากมีการซ่อนเพิ่มเติม thisพารามิเตอร์ที่

ในทางปฏิบัติสิ่งนี้สร้างความแตกต่างเพียงเล็กน้อยที่จะซ่อนอยู่ในเสียงรบกวนของการตัดสินใจของคอมไพเลอร์ต่างๆ (ดังนั้นคนสองคนสามารถ "พิสูจน์" ได้คนหนึ่งดีกว่าอีกคนด้วยผลลัพธ์ที่ไม่เห็นด้วย) ไม่น้อยตั้งแต่thisปกติจะถูกส่งผ่านในการลงทะเบียนและมักจะอยู่ในการลงทะเบียนนั้นเพื่อเริ่มต้นด้วย

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

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

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

หมายเลข 2 ไม่มีความแตกต่าง มีค่าใช้จ่ายต่อคลาสจำนวนหนึ่งสำหรับสมาชิกแต่ละคนโดยมีเงื่อนไขทั้งจำนวนข้อมูลเมตาที่มีอยู่จำนวนรหัสที่มีอยู่ในไฟล์ DLL หรือ EXE จริงและจะมีรหัส jitted เท่าใด เช่นเดียวกันไม่ว่าจะเป็นอินสแตนซ์หรือแบบคงที่

ด้วยข้อ 3 thisเป็นไปตามที่thisกำหนด อย่างไรก็ตามหมายเหตุ:

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

  2. เนื่องจากเป็นที่ชัดเจนว่าthisไม่ใช่ null จึงอาจใช้เพื่อเพิ่มประสิทธิภาพการโทรในบางกรณี

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

  4. ที่กล่าวว่าการตรวจสอบเป็นโมฆะมีราคาถูก!

เป็นที่น่าสังเกตว่าวิธีการแบบคงที่ทั่วไปที่ทำหน้าที่กับวัตถุแทนที่จะเป็นวิธีการของอินสแตนซ์สามารถลดค่าใช้จ่ายบางส่วนที่กล่าวถึงในhttp://joeduffyblog.com/2011/10/23/on-generics-and-some-of- ค่าโสหุ้ยที่เกี่ยวข้อง /ในกรณีที่ค่าคงที่ที่กำหนดไม่ได้ถูกเรียกสำหรับประเภทที่กำหนด ในขณะที่เขากล่าวว่า "นอกเหนือจากนั้นปรากฎว่าวิธีการขยายเป็นวิธีที่ยอดเยี่ยมในการทำให้ abstractions ทั่วไปจ่ายเงินเพื่อเล่นมากขึ้น"

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

สรุป:

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

แก้ไข: หมายเหตุเกี่ยวกับการตรวจสอบโมฆะราคาถูก (ซึ่งฉันอ้างไว้ข้างต้น) การตรวจสอบค่า null ส่วนใหญ่ใน. NET ไม่ได้ตรวจสอบค่าว่างเลย แต่จะดำเนินการต่อในสิ่งที่พวกเขากำลังจะทำโดยสมมติว่ามันจะใช้งานได้และหากข้อยกเว้นการเข้าถึงเกิดขึ้นมันจะกลายเป็นไฟล์NullReferenceException. ด้วยเหตุนี้ส่วนใหญ่เมื่อแนวคิดรหัส C # เกี่ยวข้องกับการตรวจสอบค่าว่างเนื่องจากมีการเข้าถึงสมาชิกอินสแตนซ์ค่าใช้จ่ายหากประสบความสำเร็จจริงจะเป็นศูนย์ ข้อยกเว้นคือการโทรแบบอินไลน์ (เพราะพวกเขาต้องการทำตัวราวกับว่าพวกเขาเรียกว่าสมาชิกอินสแตนซ์) และพวกเขาเพียงแค่กดฟิลด์เพื่อเรียกใช้พฤติกรรมเดียวกันดังนั้นพวกเขาจึงมีราคาถูกมากและพวกเขาก็ยังสามารถถูกทิ้งได้อยู่ดี (เช่นหากขั้นตอนแรกในวิธีการนี้เกี่ยวข้องกับการเข้าถึงเขตข้อมูลเหมือนเดิม)


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

@scriptocalypse ไม่ได้จริงๆ แคชคำสั่งจะไม่เห็นความแตกต่างใด ๆ และในระดับนั้นไม่มีความแตกต่างมากนักระหว่างการเข้าถึงข้อมูลผ่านthisหรือผ่านพารามิเตอร์ที่ชัดเจน ผลกระทบที่ยิ่งใหญ่กว่านี้คือการที่ข้อมูลใกล้เคียงกับข้อมูลที่เกี่ยวข้อง (ฟิลด์ชนิดค่าหรือค่าอาร์เรย์อยู่ใกล้กว่าข้อมูลในฟิลด์ประเภทการอ้างอิง) และรูปแบบการเข้าถึง
จอนฮันนา

"ในทางทฤษฎีเราควรคาดหวังว่าวิธีการคงที่ที่ใช้วัตถุเป็นพารามิเตอร์และทำบางสิ่งบางอย่างกับมันเพื่อให้ดีน้อยกว่าการเทียบเท่ากับอินสแตนซ์บนวัตถุเดียวกันนั้นเล็กน้อย" - คุณหมายความว่าหากวิธีการตัวอย่างข้างต้นใช้ พารามิเตอร์เป็นวัตถุแทนสตริงไม่คงที่จะดีกว่าหรือไม่? ตัวอย่างเช่นฉันมีวิธีการคงที่ของฉันใช้วัตถุเป็นพารามิเตอร์และทำให้เป็นอนุกรมเป็นสตริงและส่งคืนสตริง คุณแนะนำให้ใช้แบบไม่คงที่ในกรณีนี้หรือไม่?
batmaci

1
@batmaci ฉันหมายความว่ามีโอกาสที่ดีที่obj.DoSomehting(2)จะถูกกว่าเล็กน้อยDoSomething(obj, 2)แต่อย่างที่ฉันบอกว่าความแตกต่างนั้นเล็กน้อยมากและขึ้นอยู่กับสิ่งเล็ก ๆ น้อย ๆ ที่อาจแตกต่างกันในการรวบรวมขั้นสุดท้ายซึ่งไม่ควรกังวลเลย หากคุณกำลังทำอะไรบางอย่างที่มีราคาแพง (เทียบกับประเภทของความแตกต่างในการเล่นที่นี่) ในฐานะที่เป็นอนุกรมกับสตริงก็จะไม่มีจุดหมายโดยเฉพาะอย่างยิ่ง
จอนฮันนา

อาจมีสิ่งหนึ่งที่อาจชัดเจน แต่สิ่งสำคัญที่ขาดหายไปในคำตอบที่ยอดเยี่ยมนี้: วิธีการของอินสแตนซ์ต้องใช้อินสแตนซ์และการสร้างอินสแตนซ์นั้นไม่ถูก แม้แต่ค่าเริ่มต้นctorก็ยังต้องการการเริ่มต้นของฟิลด์ทั้งหมด เมื่อคุณมีอินสแตนซ์แล้วคำตอบนี้จะใช้ได้ ("สิ่งอื่น ๆ ทั้งหมดเท่ากัน") แน่นอนว่าราคาแพงcctorสามารถทำให้วิธีการคงที่ช้าได้เช่นกัน แต่นั่นเป็นเพียงการเรียกครั้งแรกเท่านั้นที่ใช้กับวิธีการอินสแตนซ์เท่ากัน ดูdocs.microsoft.com/en-us/previous-versions/dotnet/articles/…
Abel

9

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

ฉันจะบอกว่าใช่ ในการประกาศบางสิ่งที่staticคุณประกาศเจตนาของการประหารชีวิตแบบไร้สัญชาติ (ไม่ได้บังคับ แต่เป็นเจตนาของสิ่งที่เราคาดหวัง)

ในกรณีที่มีคลาสสแตติกเหล่านี้จำนวนมาก (เช่น 100 ซึ่งมีวิธีการคงที่หลายวิธี) สิ่งนี้จะส่งผลต่อประสิทธิภาพการดำเนินการหรือการใช้หน่วยความจำในทางลบเมื่อเทียบกับคลาสอินสแตนซ์จำนวนเดียวกันหรือไม่

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

เมื่อใช้คีย์เวิร์ด [this] เพื่อเรียกเมธอดอื่นภายในคลาสอินสแตนซ์เดียวกันการแก้ปัญหาอินสแตนซ์ยังคงเกิดขึ้นหรือไม่

ไม่แน่ใจเกี่ยวกับประเด็นนี้ (นี่เป็นรายละเอียดการใช้งาน CLR ล้วนๆ) แต่คิดว่าใช่


วิธีการคงที่ไม่สามารถเยาะเย้ยได้หากคุณทำ TDD หรือเพียงแค่ทดสอบหน่วยสิ่งนี้จะส่งผลเสียต่อการทดสอบของคุณมาก
trampster

@trampster ทำไม? มันเป็นเพียงส่วนหนึ่งของตรรกะ คุณสามารถล้อเลียนสิ่งที่คุณให้มันได้อย่างง่ายดาย? เพื่อให้ได้พฤติกรรมที่ถูกต้อง และวิธีการคงที่จำนวนมากจะเป็นตรรกะส่วนตัวในฟังก์ชันอยู่ดี
M. Mimpen

@ M.Mimpen ตราบใดที่คุณปล่อยให้มันเป็นชิ้นส่วนตัวเล็ก ๆ ก็ดีถ้าเป็นวิธีสาธารณะและคุณใช้จากการปิดอื่น ๆ และจำเป็นต้องเปลี่ยนสิ่งที่ทำในการทดสอบของคุณจากนั้นสิ่งที่คุณติดอยู่เช่นไฟล์ IO หรือการเข้าถึงฐานข้อมูล หรือการโทรเครือข่าย ฯลฯ หากใส่ในวิธีการแบบคงที่จะไม่สามารถลอกเลียนแบบได้เว้นแต่คุณจะบอกว่าคุณฉีดการพึ่งพาที่สามารถจำลองได้เป็นพารามิเตอร์ให้กับวิธีการแบบคงที่
trampster

-2

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


17
คุณไม่มีข้อโต้แย้งใด ๆ กับการเรียกร้องของคุณ
ymajoros

2
@ fjch1997 ผู้โหวต 2 คนดูเหมือนจะคิดเป็นอย่างอื่น (เพื่อสิ่งที่คุ้มค่า) การแสดงความคิดเห็น downvotes สนับสนุนให้ฝึกฝนบน stackexchange: meta.stackexchange.com/questions/135/…
ymajoros
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.