Apa yang terjadi di balik layar ketika Anda menandai ekspresi reguler sebagai yang akan dikompilasi? Bagaimana ini membandingkan / berbeda dari ekspresi reguler di-cache?
Dengan menggunakan informasi ini, bagaimana Anda menentukan kapan biaya perhitungan dapat diabaikan dibandingkan dengan peningkatan kinerja?
Jawaban:
RegexOptions.Compiled
menginstruksikan mesin ekspresi reguler untuk mengkompilasi ekspresi ekspresi reguler ke IL menggunakan generasi kode ringan ( LCG ). Kompilasi ini terjadi selama konstruksi objek dan sangat memperlambatnya. Pada gilirannya, kecocokan menggunakan ekspresi reguler lebih cepat.Jika Anda tidak menentukan tanda ini, ekspresi reguler Anda dianggap "ditafsirkan".
Ambil contoh ini:
Ia melakukan 4 tes pada 3 ekspresi reguler yang berbeda. Pertama menguji satu pertandingan sekali (dikompilasi vs tidak dikompilasi). Kedua, tes ini mengulangi kecocokan yang menggunakan kembali persamaan reguler yang sama.
Hasil di mesin saya (dikompilasi dalam rilis, tidak ada debugger terpasang)
1000 pertandingan tunggal (buat Regex, Cocokkan dan buang)
1.000.000 kecocokan - menggunakan kembali objek Regex
Hasil ini menunjukkan bahwa ekspresi reguler yang dikompilasi dapat mencapai 60% lebih cepat untuk kasus di mana Anda menggunakan kembali
Regex
objek. Namun dalam beberapa kasus bisa lebih dari 3 urutan besarnya lebih lambat untuk dibangun.Ini juga menunjukkan bahwa versi .NET x64 bisa 5 sampai 6 kali lebih lambat ketika datang ke kompilasi ekspresi reguler.
Rekomendasi akan menggunakan versi yang dikompilasi dalam kasus di mana baik
Spanner dalam karya, cache regex
Mesin ekspresi reguler berisi cache LRU yang menampung 15 ekspresi reguler terakhir yang diuji menggunakan metode statis di
Regex
kelas.Sebagai contoh:
Regex.Replace
,Regex.Match
dll .. semua menggunakan cache Regex.Ukuran cache dapat ditingkatkan dengan pengaturan
Regex.CacheSize
. Ini menerima perubahan ukuran setiap saat selama siklus hidup aplikasi Anda.Ekspresi reguler baru hanya di-cache oleh pembantu statis di kelas Regex. Namun, jika Anda membuat objek, cache diperiksa (untuk digunakan kembali dan dihantam), ekspresi reguler yang Anda buat tidak ditambahkan ke cache .
Cache ini adalah cache LRU yang sepele , ini diimplementasikan menggunakan daftar ditautkan sederhana. Jika Anda meningkatkannya menjadi 5.000, dan menggunakan 5.000 panggilan berbeda pada pembantu statis, setiap konstruksi ekspresi reguler akan merayapi 5.000 entri untuk melihat apakah sebelumnya telah di-cache. Ada kunci di sekitar cek, sehingga pemeriksaan dapat mengurangi paralelisme dan memperkenalkan pemblokiran ulir.
Jumlahnya diatur cukup rendah untuk melindungi diri dari kasus-kasus seperti ini, meskipun dalam beberapa kasus Anda mungkin tidak punya pilihan selain menambahnya.
Rekomendasi kuat saya tidak akan pernah meneruskan
RegexOptions.Compiled
opsi ke pembantu statis.Sebagai contoh:
Alasannya adalah Anda berisiko besar kehilangan cache LRU yang akan memicu kompilasi yang sangat mahal . Selain itu, Anda tidak tahu apa yang perpustakaan Anda tergantung pada melakukan, sehingga memiliki sedikit kemampuan untuk kontrol atau memprediksi terbaik ukuran cache.
Lihat juga: blog tim BCL
Catatan : ini relevan untuk .NET 2.0 dan .NET 4.0. Ada beberapa perubahan yang diharapkan pada 4,5 yang dapat menyebabkan ini direvisi.
sumber
Compiled
kode situs web di mana saya sebenarnya menyimpan objek statis (aplikasi-lebar)Regex
. JadiRegex
satu - satunya harus dibangun sekali ketika IIS memulai aplikasi, dan kemudian digunakan kembali ribuan kali. Ini berfungsi dengan baik selama aplikasi tidak sering restart.Entri ini di Blog Tim BCL memberikan gambaran yang bagus: " Performa Ekspresi Reguler ".
Singkatnya, ada tiga jenis regex (masing-masing menjalankan lebih cepat dari yang sebelumnya):
ditafsirkan
cepat untuk membuat dengan cepat, lambat untuk dieksekusi
dikompilasi (yang sepertinya Anda tanyakan)
lebih lambat untuk membuat dengan cepat, cepat untuk mengeksekusi (baik untuk eksekusi dalam loop)
pra-kompilasi
buat pada waktu kompilasi aplikasi Anda (tidak ada penalti penciptaan run-time), cepat dijalankan
Jadi, jika Anda bermaksud menjalankan regex hanya sekali, atau di bagian non-kinerja-kritis dari aplikasi Anda (yaitu validasi input pengguna), Anda setuju dengan opsi 1.
Jika Anda bermaksud menjalankan regex dalam satu lingkaran (yaitu penguraian file baris demi baris), Anda harus memilih opsi 2.
Jika Anda memiliki banyak regex yang tidak akan pernah berubah untuk aplikasi Anda dan digunakan secara intensif, Anda bisa menggunakan opsi 3.
sumber
CompileModule
. Sial, saya perlu melihat lebih dalam ke plattform baru.Perlu dicatat bahwa kinerja ekspresi reguler sejak .NET 2.0 telah ditingkatkan dengan cache MRU dari ekspresi reguler yang tidak dikompilasi. Kode pustaka Regex tidak lagi menginterpretasi ulang ekspresi reguler yang sama yang tidak dikompilasi setiap waktu.
Jadi ada potensi penalti kinerja yang lebih besar dengan ekspresi reguler terkompilasi dan on the fly. Selain waktu muat yang lebih lambat, sistem juga menggunakan lebih banyak memori untuk mengkompilasi ekspresi reguler ke opcode.
Pada dasarnya, saran saat ini adalah jangan mengkompilasi ekspresi reguler, atau mengkompilasi terlebih dahulu ke majelis terpisah.
Ref: Blog BCL Team Kinerja ekspresi reguler [David Gutierrez]
sumber
1) Tim Perpustakaan Kelas Dasar pada regex yang dikompilasi
2) Coding Horror, merujuk # 1 dengan beberapa poin bagus pada kompromi
sumber
Saya harap kode di bawah ini akan membantu Anda memahami konsep fungsi kompilasi ulang
sumber