Saya menemukan artikel ini tentang Lazy
: Kemalasan dalam C # 4.0 - Malas
Apa praktik terbaik untuk mendapatkan kinerja terbaik menggunakan objek Malas? Bisakah seseorang mengarahkan saya ke penggunaan praktis dalam aplikasi nyata? Dengan kata lain, kapan saya harus menggunakannya?
c#
.net
lazy-evaluation
danyolgiax
sumber
sumber
get { if (foo == null) foo = new Foo(); return foo; }
. Dan ada zillions tempat yang memungkinkan untuk menggunakannya ...get { if (foo == null) foo = new Foo(); return foo; }
tidak aman untuk thread, sementaraLazy<T>
thread-safe secara default.Jawaban:
Anda biasanya menggunakannya ketika Anda ingin instantiate sesuatu pertama kali itu benar-benar digunakan. Ini menunda biaya pembuatannya sampai jika / saat dibutuhkan alih-alih selalu menimbulkan biaya.
Biasanya ini lebih disukai ketika objek mungkin atau mungkin tidak digunakan dan biaya membangun itu tidak sepele.
sumber
Lazy<T>
. Namun, untuk membuat masing-masing properti saya melakukan interpolasi linier (atau interpolasi bilinear) yang cukup sepele tetapi memang memiliki beberapa biaya. (Apakah Anda akan menyarankan agar saya pergi dan melakukan eksperimen sendiri?)Anda harus mencoba menghindari penggunaan lajang, tetapi jika Anda memang perlu melakukannya,
Lazy<T>
membuat penerapan lajang yang malas dan aman di thread:sumber
Sebuah contoh dunia nyata yang hebat di mana lazy loading berguna adalah dengan ORM (Object Relation Mappers) seperti Entity Framework dan NHibernate.
Katakanlah Anda memiliki entitas Pelanggan yang memiliki properti untuk Nama, Nomor Telepon, dan Pesanan. Nama dan Nomor Telepon adalah string biasa tetapi Pesanan adalah properti navigasi yang mengembalikan daftar setiap pesanan yang pernah dibuat pelanggan.
Anda mungkin sering ingin mengunjungi semua pelanggan Anda dan mendapatkan nama dan nomor telepon mereka untuk menelepon mereka. Ini adalah tugas yang sangat cepat dan sederhana, tetapi bayangkan jika setiap kali Anda membuat pelanggan secara otomatis pergi dan melakukan kompleks bergabung untuk mengembalikan ribuan pesanan. Bagian terburuknya adalah Anda bahkan tidak akan menggunakan pesanan sehingga itu adalah pemborosan sumber daya!
Ini adalah tempat yang tepat untuk pemuatan malas karena jika properti Order malas, tidak akan mengambil semua pesanan pelanggan kecuali Anda benar-benar membutuhkannya. Anda dapat menghitung objek Pelanggan hanya mendapatkan Nama dan Nomor Telepon mereka saat properti Order dengan sabar tidur, siap ketika Anda membutuhkannya.
sumber
Db.Customers.Include("Orders")
. Ini akan menyebabkan pesanan bergabung dieksekusi pada saat itu daripada saatCustomer.Orders
properti pertama kali digunakan. Pemuatan Malas juga dapat dinonaktifkan melalui DbContext.Saya telah mempertimbangkan untuk menggunakan
Lazy<T>
properti untuk membantu meningkatkan kinerja kode saya sendiri (dan untuk belajar lebih banyak tentangnya). Saya datang ke sini mencari jawaban tentang kapan menggunakannya tetapi tampaknya ke mana pun saya pergi ada frasa seperti:dari MSDN Lazy <T> Class
Saya sedikit bingung karena saya tidak yakin di mana harus menarik garis. Sebagai contoh, saya menganggap interpolasi linier sebagai perhitungan yang cukup cepat tetapi jika saya tidak perlu melakukannya, dapatkah inisialisasi malas membantu saya menghindari melakukannya dan apakah itu layak?
Pada akhirnya saya memutuskan untuk mencoba tes saya sendiri dan saya pikir saya akan membagikan hasilnya di sini. Sayangnya saya tidak benar-benar ahli dalam melakukan tes semacam ini dan jadi saya senang mendapatkan komentar yang menyarankan perbaikan.
Deskripsi
Untuk kasus saya, saya sangat tertarik untuk melihat apakah Properti Malas dapat membantu meningkatkan bagian dari kode saya yang melakukan banyak interpolasi (sebagian besar tidak digunakan) dan jadi saya telah membuat tes yang membandingkan 3 pendekatan.
Saya membuat kelas tes terpisah dengan 20 properti uji (sebut saja properti-t) untuk setiap pendekatan.
Hasil tes diukur dalam ms dan rata-rata 50 instansi atau 20 properti dapatkan. Setiap tes kemudian dijalankan 5 kali.
Hasil Tes 1: Instansiasi (rata-rata 50 Instansiasi)
Hasil Tes 2: First Get (rata-rata 20 properti mendapat)
Hasil Uji 3: Get Kedua (rata-rata 20 properti mendapat)
Pengamatan
GetInterp
lebih cepat untuk instantiate seperti yang diharapkan karena tidak melakukan apa pun.InitLazy
lebih cepat untuk instantiate daripadaInitInterp
menyarankan bahwa overhead dalam mengatur properti malas lebih cepat daripada perhitungan interpolasi linier saya. Namun, saya agak bingung di sini karenaInitInterp
harus melakukan 20 interpolasi linier (untuk mengatur itu t-properti) tetapi hanya butuh 0,09 ms untuk instantiate (tes 1), dibandingkan denganGetInterp
yang membutuhkan 0,28 ms untuk melakukan hanya satu interpolasi linier pertama kali (tes 2), dan 0,1 ms untuk melakukannya kedua kalinya (tes 3).Dibutuhkan
InitLazy
hampir 2 kali lebih lama daripadaGetInterp
untuk mendapatkan properti pertama kali, sedangkanInitInterp
yang tercepat, karena dihuni properti selama instantiasi. (Setidaknya itu yang seharusnya dilakukan tetapi mengapa hasil instantiasi jauh lebih cepat daripada interpolasi linier tunggal? Kapan tepatnya melakukan interpolasi ini?)Sayangnya sepertinya ada beberapa optimasi kode otomatis yang terjadi dalam pengujian saya. Perlu waktu
GetInterp
yang sama untuk mendapatkan properti pertama kali seperti halnya yang kedua kalinya, tetapi itu menunjukkan lebih dari 2x lebih cepat. Sepertinya optimasi ini juga mempengaruhi kelas-kelas lain juga karena mereka semua mengambil jumlah waktu yang sama untuk pengujian 3. Namun, optimisasi semacam itu juga dapat terjadi dalam kode produksi saya sendiri yang mungkin juga menjadi pertimbangan penting.Kesimpulan
Sementara beberapa hasil seperti yang diharapkan, ada juga beberapa hasil tak terduga yang sangat menarik mungkin karena optimisasi kode. Bahkan untuk kelas yang terlihat seperti mereka melakukan banyak pekerjaan di konstruktor, hasil instantiasi menunjukkan bahwa mereka mungkin masih sangat cepat untuk membuat, dibandingkan dengan mendapatkan properti ganda. Sementara para ahli di bidang ini mungkin dapat berkomentar dan menginvestigasi lebih menyeluruh, perasaan pribadi saya adalah bahwa saya perlu melakukan tes ini lagi tetapi pada kode produksi saya untuk memeriksa jenis optimisasi apa yang mungkin terjadi di sana juga. Namun, saya berharap itu
InitInterp
mungkin jalan yang harus ditempuh.sumber
lazy
harus melakukan beberapa pembukuan tambahan,InitLazy
akan menggunakan lebih banyak memori daripada solusi lainnya. Mungkin juga memiliki hit kinerja kecil pada setiap akses, sementara memeriksa apakah sudah memiliki nilai atau tidak; Trik yang cerdik bisa menghilangkan overhead itu, tetapi akan membutuhkan dukungan khusus di IL. (Haskell melakukan ini dengan membuat setiap nilai malas panggilan fungsi; setelah nilai dihasilkan, itu diganti dengan fungsi yang mengembalikan nilai itu setiap waktu.)Untuk menunjukkan contoh yang diposting oleh Mathew
sebelum Malas lahir kita akan melakukannya dengan cara ini:
sumber
Dari MSDN:
Selain jawaban James Michael Hare, Lazy memberikan inisialisasi aman untuk nilai Anda. Lihatlah enumerasi entri MSDN LazyThreadSafetyMode yang menjelaskan berbagai jenis mode keselamatan ulir untuk kelas ini.
sumber
Anda harus melihat contoh ini untuk memahami arsitektur Lazy Loading
-> output -> 0 1 2
tetapi jika kode ini jangan tulis "list.Value.Add (0);"
output -> Nilai tidak dibuat
sumber