Performa metode statis vs metode instance

108

Pertanyaan saya berkaitan dengan karakteristik kinerja metode statis vs metode contoh dan skalabilitasnya. Asumsikan untuk skenario ini bahwa semua definisi kelas berada dalam satu rakitan dan beberapa jenis penunjuk diskrit diperlukan.

Mempertimbangkan:

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.
}

Kelas-kelas di atas mewakili pola gaya helper.

Dalam kelas instance, menyelesaikan metode instance membutuhkan waktu beberapa saat untuk dilakukan sebagai lawan dari StaticClass.

Pertanyaan saya adalah:

  1. Saat mempertahankan status tidak menjadi perhatian (tidak ada bidang atau properti yang diperlukan), apakah selalu lebih baik menggunakan kelas statis?

  2. Di mana terdapat sejumlah besar definisi kelas statis ini (misalnya 100, dengan sejumlah metode statis masing-masing) akankah hal ini mempengaruhi kinerja eksekusi atau konsumsi memori secara negatif dibandingkan dengan jumlah definisi kelas instance yang sama?

  3. Ketika metode lain dalam kelas instance yang sama dipanggil, apakah resolusi instance masih terjadi? Misalnya menggunakan kata kunci [ini] seperti this.DoOperation2("abc")dari dalam DoOperation1contoh yang sama.

Bernie White
sumber
apa yang Anda maksud dengan "resolusi contoh"? Pada level IL, pointer "ini" tersedia seperti variabel lokal lainnya. Faktanya, pada beberapa versi CLR / JIT lama, Anda dapat memanggil metode-instance pada NULL asalkan tidak menyentuh 'ini' - kode hanya terbang dan tidak berfungsi apa pun .. sekarang CLR / JIT berisi null- eksplisit periksa setiap permintaan anggota ..
quetzalcoatl
> vijaymukhi.com/documents/books/ilbook/chap8.htm dan 'call instance' versus 'call' saja. Yang pertama mengharapkan parameter 'ini' dan yang terakhir - tidak.
quetzalcoatl
@Quetzalcoatl maaf atas kebingungan ini, pertanyaannya adalah lebih banyak metode untuk metode dari contoh yang sama dan jika itu memerlukan contoh untuk diselesaikan sendiri.
Bernie White
1
@quetzalcoatl Saya berasumsi maksudnya, "apakah kompilator menyingkirkan pemeriksaan yang thismenunjuk ke sesuatu ketika kelas memanggil metode instance pada dirinya sendiri?"
Jon Hanna

Jawaban:

152

Secara teori, metode statis harus bekerja sedikit lebih baik daripada metode instance, semua hal lain dianggap sama, karena thisparameter tersembunyi ekstra .

Dalam praktiknya, ini hanya membuat sedikit perbedaan sehingga akan tersembunyi dalam kebisingan berbagai keputusan compiler. (Oleh karena itu, dua orang dapat "membuktikan" yang satu lebih baik daripada yang lain dengan hasil yang tidak setuju). Paling tidak karena thisbiasanya diteruskan dalam register dan sering kali dalam register itu untuk memulai.

Poin terakhir ini berarti bahwa dalam teori, kita harus mengharapkan metode statis yang mengambil objek sebagai parameter dan melakukan sesuatu dengannya menjadi sedikit kurang baik daripada yang setara sebagai instance pada objek yang sama. Sekali lagi, perbedaannya sangat kecil sehingga jika Anda mencoba mengukurnya, Anda mungkin akan mengukur beberapa keputusan compiler lainnya. (Terutama karena kemungkinan jika referensi itu berada dalam register sepanjang waktu juga cukup tinggi).

Perbedaan kinerja sebenarnya akan turun ke apakah Anda memiliki objek secara artifisial dalam memori untuk melakukan sesuatu yang seharusnya statis, atau Anda menjerat rantai pengoperan objek dengan cara yang rumit untuk melakukan apa yang seharusnya secara alami menjadi contoh.

Oleh karena itu untuk nomor 1. Ketika menjaga status bukanlah masalah, selalu lebih baik untuk menjadi statis, karena untuk itulah statis . Ini bukan masalah kinerja, meskipun ada aturan keseluruhan untuk bermain baik dengan pengoptimalan kompiler - kemungkinan besar seseorang berusaha mengoptimalkan kasus yang muncul dengan penggunaan normal daripada kasus yang muncul dengan penggunaan aneh.

Nomor 2. Tidak ada bedanya. Ada sejumlah biaya per kelas untuk setiap anggota, baik dari segi berapa banyak metadata yang ada, berapa banyak kode yang ada dalam file DLL atau EXE yang sebenarnya, dan berapa banyak kode jitted yang ada. Ini sama apakah itu instance atau statis.

Dengan item 3, thisseperti thishalnya. Namun perhatikan:

  1. The thisparameter dilewatkan di register tertentu. Saat memanggil metode instance dalam kelas yang sama, kemungkinan besar sudah ada di register itu (kecuali jika disimpan dan register digunakan untuk beberapa alasan) dan karenanya tidak ada tindakan yang diperlukan untuk menyetel thiske apa yang perlu disetel ke . Ini berlaku sampai batas tertentu misalnya, dua parameter pertama pada metode menjadi dua parameter pertama dari panggilan yang dibuatnya.

  2. Karena akan jelas bahwa thisini bukan null, ini dapat digunakan untuk mengoptimalkan panggilan dalam beberapa kasus.

  3. Karena akan jelas bahwa thisitu bukan null, ini dapat membuat pemanggilan metode sebaris lebih efisien lagi, karena kode yang dihasilkan untuk memalsukan pemanggilan metode dapat menghilangkan beberapa pemeriksaan nol yang mungkin diperlukan.

  4. Konon, cek nol itu murah!

Perlu dicatat bahwa metode statis generik yang bekerja pada suatu objek, daripada metode instan, dapat mengurangi beberapa biaya yang dibahas di http://joeduffyblog.com/2011/10/23/on-generics-and-some-of- overhead-terkait / dalam kasus di mana statis yang diberikan tidak dipanggil untuk jenis tertentu. Seperti yang dia katakan, "Sebagai tambahan, ternyata metode penyuluhan adalah cara yang bagus untuk membuat abstraksi umum lebih menguntungkan."

Namun, perhatikan bahwa ini hanya berkaitan dengan instansiasi tipe lain yang digunakan oleh metode, yang sebaliknya tidak ada. Dengan demikian, ini benar-benar tidak berlaku untuk banyak kasus (beberapa metode contoh lain menggunakan tipe itu, beberapa kode lain di tempat lain menggunakan tipe itu).

Ringkasan:

  1. Sebagian besar biaya kinerja instans vs statis di bawah dapat diabaikan.
  2. Biaya yang ada biasanya akan datang jika Anda menyalahgunakan statis misalnya atau sebaliknya. Jika Anda tidak menjadikannya bagian dari keputusan Anda antara statis dan instance, kemungkinan besar Anda akan mendapatkan hasil yang benar.
  3. Ada kasus yang jarang terjadi di mana metode generik statis di tipe lain menghasilkan lebih sedikit tipe yang dibuat, daripada metode generik contoh, yang membuatnya terkadang memiliki manfaat kecil untuk mengubah yang jarang digunakan (dan "jarang" mengacu pada tipe yang digunakan dengannya di masa pakai aplikasi, bukan seberapa sering dipanggil). Setelah Anda mendapatkan apa yang dia bicarakan di artikel itu, Anda akan melihat bahwa itu 100% tidak relevan dengan sebagian besar keputusan statis-vs-contoh. Sunting: Dan sebagian besar hanya memiliki biaya dengan ngen, bukan dengan kode jitted.

Sunting: Sebuah catatan tentang betapa murahnya cek-nol (yang saya klaim di atas). Kebanyakan pemeriksaan-nol di .NET tidak memeriksa nol sama sekali, melainkan mereka melanjutkan apa yang akan mereka lakukan dengan asumsi bahwa itu akan berhasil, dan jika pengecualian akses terjadi, itu akan berubah menjadi NullReferenceException. Dengan demikian, sebagian besar ketika secara konseptual kode C # melibatkan pemeriksaan null karena mengakses anggota instance, biaya jika berhasil sebenarnya nol. Pengecualiannya adalah beberapa panggilan inline, (karena mereka ingin berperilaku seolah-olah mereka memanggil anggota instance) dan mereka baru saja menekan sebuah bidang untuk memicu perilaku yang sama, jadi panggilan tersebut juga sangat murah, dan mereka masih sering ditinggalkan (misalnya jika langkah pertama dalam metode tersebut melibatkan mengakses bidang sebagaimana adanya).

Jon Hanna
sumber
Dapatkah Anda mengomentari apakah pertanyaan statis vs instance ada hubungannya dengan koherensi cache? Apakah ketergantungan pada satu atau lainnya lebih mungkin menyebabkan kehilangan cache? Apakah ada garis besar yang menjelaskan alasannya?
scriptocalypse
@scriptocal Tidak juga. Cache instruksi tidak akan melihat perbedaan apa pun, dan pada tingkat itu tidak banyak perbedaan antara mengakses data melalui thisatau melalui parameter eksplisit. Dampak yang lebih besar di sini adalah seberapa dekat data dengan data terkait (bidang tipe nilai atau nilai larik lebih dekat daripada data di bidang tipe referensi) dan pola akses.
Jon Hanna
"dalam teori, kita harus mengharapkan metode statis yang mengambil objek sebagai parameter dan melakukan sesuatu dengannya menjadi sedikit kurang baik daripada yang setara sebagai contoh pada objek yang sama." - Apakah maksud Anda jika metode sampel di atas mengambil parameter sebagai objek daripada string, non-statis lebih baik? sebagai contoh: Saya memiliki metode statis saya mengambil objek sebagai parameter dan menserialisasinya menjadi string dan mengembalikan string. apakah Anda menyarankan untuk menggunakan non-statis dalam kasus ini?
batmaci
1
@batmaci Maksud saya ada kemungkinan besar obj.DoSomehting(2)akan sedikit lebih murah daripada DoSomething(obj, 2)tetapi karena saya juga mengatakan perbedaannya sangat kecil dan sangat bergantung pada hal-hal kecil yang mungkin berakhir berbeda dalam kompilasi akhir sehingga tidak perlu dikhawatirkan sama sekali. Jika Anda melakukan sesuatu yang mahal (relatif terhadap jenis perbedaan dalam permainan di sini) seperti menserialisasikan sesuatu ke string maka itu sangat tidak berguna.
Jon Hanna
Ada satu hal, mungkin jelas, namun penting yang hilang dalam jawaban yang sangat bagus ini: metode instance membutuhkan sebuah instance, dan membuat sebuah instance tidaklah murah. Bahkan defaultnya ctormasih membutuhkan inisialisasi semua field. Setelah Anda memiliki sebuah contoh, jawaban ini berlaku ("semua hal lain dianggap sama"). Tentu saja, biaya yang mahal juga cctordapat membuat metode statis menjadi lambat, tetapi itu hanya pada panggilan pertama yang berlaku untuk metode instance secara setara. Lihat juga docs.microsoft.com/en-us/previous-versions/dotnet/articles/…
Abel
8

Saat mempertahankan status tidak menjadi perhatian (tidak ada bidang atau properti yang diperlukan), apakah selalu lebih baik menggunakan kelas statis?

Saya akan menjawab, ya. Saat mendeklarasikan sesuatu, staticAnda mendeklarasikan maksud dari eksekusi tanpa kewarganegaraan (ini tidak wajib, tetapi maksud dari sesuatu yang diharapkan)

Di mana terdapat sejumlah besar kelas statis ini (katakanlah 100 misalnya, dengan sejumlah metode statis masing-masing) apakah ini akan mempengaruhi kinerja eksekusi atau konsumsi memori secara negatif dibandingkan dengan jumlah kelas instans yang sama?

Jangan berpikir demikian, kecuali Anda yakin bahwa kelas statis benar - benar tidak stabil, karena jika tidak, akan mudah mengacaukan alokasi memori dan mendapatkan kebocoran memori.

Ketika kata kunci [ini] digunakan untuk memanggil metode lain dalam kelas instance yang sama, apakah resolusi instance masih terjadi?

Tidak yakin, tentang hal ini (ini adalah detail implementasi CLR murni), tapi pikirkan ya.

Tigran
sumber
Metode statis tidak dapat diejek, Jika Anda melakukan TDD atau bahkan hanya pengujian unit, ini akan sangat merugikan pengujian Anda.
pelacur
@trampster Mengapa? Itu hanya sepotong logika. Anda dapat dengan mudah mengejek apa yang Anda berikan? Untuk mendapatkan perilaku yang benar. Dan banyak metode statis akan menjadi bagian logika pribadi dalam suatu fungsi.
M. Mimpen
@ M.Mimpen selama Anda membiarkannya menjadi potongan pribadi kecil baik-baik saja, jika itu adalah metode publik dan Anda menggunakannya dari penutupan lain dan perlu mengubah apa yang dilakukannya dalam pengujian Anda, maka Anda macet, hal-hal seperti file IO atau akses database atau panggilan jaringan dll, jika dimasukkan ke dalam metode statis akan menjadi tidak dapat diblokir, kecuali seperti Anda mengatakan Anda menyuntikkan ketergantungan yang dapat diejek sebagai parameter ke metode statis
trampster
-2

metode statis lebih cepat tetapi kurang OOP, jika Anda akan menggunakan pola desain metode statis kemungkinan kode buruk, untuk menulis logika bisnis lebih baik tanpa statis, fungsi umum seperti membaca file, WebRequest dll lebih baik disadari sebagai statis ... Anda pertanyaan tidak memiliki universal menjawab

burning_LEGION
sumber
16
Anda tidak memberikan argumen untuk klaim Anda.
ymajoros
2
@ fjch1997 2 upvoters tampaknya berpikir sebaliknya (untuk apa nilainya). Mengomentari suara
negatif