Viewstate ile Performans

Bazı uygulamalar için önemli olan bir girdiye doğruyu çıktıyı makul bir zamanda verebilmektir, ancak ASP.NET gibi uygulama türlerinde hız ve performans çok önemli bir faktördür. Hız ve performansın ASP.NET web uygulamalarında önemli olmasının en büyük nedeni elbetteki uygulamaların web tabanlı olması ve uygulamanın çalışması için sunucudan istemciye yüklenme gerekliliğidir. Uygulamanın içerdiği lojik ve bellek yönetimi ne kadar iyi yapılırsa programın istemciye çıktıyı üretmesi o kadar hızlı olacaktır. Dolayısıyla hızlı ver performansı yüksek olan ASP.NET uygulamaları geliştirmek için geleneksel olan bazı kuralların bilinmesi ve bunların geliştirici tarafından uygulanması gerekir. Bu yazıda ASP.NET uygulamalarının performansını artıracak önemli ipuçlarından ve bazı klasik yöntemlerden bahsedeceğim.

Performans artırma işlemi kesin çizgilerle belirlenmiş bir kavram değildir. Çünkü amacımız sistemin yapabileceklerini kısıtlamadan var olan özelliklerin daha hızlı çalışmasını sağlamak. Bu yüzden bu yazıda anlatacağım bazı kaçınmamız gereken noktaları bir çok projede zaten uygulamış olabilirsiniz. Bu, projenizin yapısını değiştirmeniz gereklidir anlamına gelmez, ancak bundan sonraki projelerinizde bu tür durumlara dikkat etmeniz gerekebilir.

Şimdi sırayla uygulamamızın performansını artırabilecek faktörleri ele alalım :

1 – “Release Mode” Derlemesi Yapma

Bildiğiniz üzere .NET uygulamalarında iki tür derleme yapabilmekteyiz, Bunlar : “Debug Mode” ve “Release Mode”. Genellikle geliştirme aşamasında derleme işlemini “Debug Mode”’ da yaparız. Çünkü “Debug Mode” derlemesi programdaki bütün akışı bize görsel bir şekilde sağlar ve koddaki hataları ayıklamamızı sağlar. Tabii bunu yapabilmenin ağır bir bedeli vardır. Programın akışı ölçülebilecek derecede debug modda derlenmiş bir kodda yavaşlayacaktır. Bunun sebebi hataları ayıklayabilmemiz için çıktı dosyalarına ekstra bilgilerin(.pdb dosyaları) eklenmesi ve çalışma sırasında bu bilgilerin yorumlanmasıdır. Çoğu zaman uygulama gerçek ortamda çalıştırılmadan önce Debug Mode’dan Release Mode’a çekme işlemi unutulabiliyor. Dolayısıyla farkında olmadan büyük bir performans kaybı olmakta. Programı “Release Mode” da derlemek için Web.Config dosyasında aşağıdaki değişiklik yapılabileceği gibi VS.NET’te proje özelliklerinden “Configuration Properties” seçeneğinden aktif halae getirilebilir.

<compilation

defaultLanguage=”c#”

debug=”true”

/>

dsa

2 – Object Veri Tipini İhtiyaç Dahilinde Kullanmak

.NET platformunda her ver tipi Object sınıfından türediği için herhangi bir değişkeni veya nesneyi object türünden bir değişkene atayabiliriz. Ancak object türü referans türü olduğu için int, byte ve double gibi temel veri tiplerini kolaylık olsun diye Object türünden değişkenlere atamamalıyız. Zira int,byte ve double gibi değer türleri belleğin stack dediğimiz bölgesinde saklanırken, sınıflar ve object türden nesneler belleğin heap bellek bölgesinde saklanır. Mimari olarak farklı tasarlanmış iki bellek bölgesi arasında veri alışverişi şu anki belleklerde her ne kadar çok fazla hız kaybı yaratmasa da bu tür işlemlerin çok sık yapıldığı döngü gibi yapılarda önemli sayılabilecek bir performans kaybı olabilir.

3 – “String” Ekleme İşlemlerinde “StringBuilder” Kullanmak

String işlemleri her uygulamada sık sık yapılan işlemlerdir. Özellikle birden fazla yazıyı ard arda yapıştırma işlemi çok sık yapılan işlemlerdir. String veri türünün çok özel bir durumu vardır : İki yazıyı + operatörüyle ard arda eklediğinizde sonuç olarak yeni bir string değişkeni döndürülür ve ard arda eklenen diğer iki string bellekte orjinal halleriyle kalır. Bir örnek verelim:

string yazi1 = “csharp”;
string yazi2 = “nedir.com”;

string yazi1 = yazi1 + yazi2;

Bu örnekte 3.satırdaki atama ile yazi1 değişkenine iki yazının birleştirilmiş hali eklenecektir. Buraya kadar her şey normal. Ancak genelde şu şekilde bir yanılgı olmaktadır. Programın icrası 3. satıra geldiğinde yazi1 değişkenin son karakterinden sonraki bölümüne yazi2 eklenecektir. Ve dolayısıyla artık bellekte “csharp” diye bir yazı kalmayacaktır. Ama bu böyle değildir. yazi1 değişkeni için bellekte yeni bir bölge tahsis edilir ve yazi1 ile yazi2 birleştirilip bu birleşmiş yazının başlangıç adresi yazi1’in referansına atanır. Dolayısıyla biz farkında olmasak ta bellekte bu işlemden sonra “csharp”,”nedir” ve “csharpnedir” olmak üzere 3 tane string değişkeni bulunmaktadır. Tabi biz “csharp” yazısını içinde tutan yazi1 değişkenine olan referansımızı kaybettiğimiz için 3. satırdan sonra “csharp” yazısına erişemeyiz.

Verilen örnekte herhangi bir performans kaybının olmayacağı açıktır. Ancak döngülerle metin dosyaları gibi büyük veri kümeleri üzerinde işlem yapıyorsak bunun etkisini çok rahatlıkla hissedebiliriz. Bu tür bir etkiyi azaltmak için .NET sınıf kütüphanesinde System.Text isim alanında StringBuilder isminde bir sınıf bulunmaktadır. Bu sınıfın Append metodunu kullanarak iki yazıyı daha etkin bir şekilde birleştirebiliriz. Sonuç olarak eğer bir program içinde yirmiden fazla uzun yazı dizisi birleştiriliyorsa her iki metodun arasında fark rahatlıkla ölçülebilecek durumua gelmektedir.

İki yöntem arasındaki farkı daha iyi anlamak için okumanızı önerdiğim yazı :Metin(String) İşlemlerinde Performansı Artırmak

4 – ViewState’in Etkin Kullanımı

ASP.NET’in en önemli yeni kavramlarından birisi de ViewState’dir. ViewState, web kontrollerinin HTTP istekleri sırasında içeriklerinin sunucuya postalanması bittiği anda HTML çıktısına eklenen veri kümesidir. ViewState özelliği aktif olan web kontollerinin bulunduğu bir form herhangi bir şekilde yeniden yüklenmesi sağlansa bile kontollerin içeriği değişmeyecektir. Halbuki klasik yöntemlerle sunucudan gelen çıktıda bu tür bir eklenti olmamaktadır. ViewState’in gereksiz yere aktif halde kalması büyük bir performans kaybına sebeb olacaktır. Çünkü web formu sunucuya postalandıktan sonra web kontrollerinin ve web formlarının içeriği ViewState’teki bilgilere göre yeniden yüklenir ve işlemler bundan sonra devam eder. Ayrıca ViewState bilgileri DatGrid gibi içerisinde çok fazla veri bulunduran web kontrolleri ile birlikte çok fazla şişecektir. ViewState verisine ihtiyacımız yokken bu verilerin sunucuda oluşmasını sağlamak gereksiz veri trafiği yaratcağı için bu durumlarda kontrolün yada web formunun ViewState özelliğini pasif hale getirmeliyiz.

Bütün Web kontrollerinin bool türünden EnableViewState adında bir özelliği bulunmaktadır. Bu özelliği false yaparak ViewState bilgisinin ilgili kontrol için oluşmamasını engelleyebiliriz. Eğer ViewState özelliğini bütün form için pasif konuma getirmek istiyorsak web formunun Page direktifinden sonra aşağıdaki gibi kullanım mevcuttur.

<@Page EnableViewState = “false”@>

5 – Oturum(Session) Nesnesinin Etkin Kullanımı

Hemen hemen bütün türden web uygulamasında Session nesnesi kullanılmaktadır. Session nesnesine yazmak ve session nesnesinden okuma yapmak sunucu açısından o kadar da kolay bir iş değildir. Session nesnesinin aktif olduğu her bir sayfa sunucuya ek yük bindirmektedir. Bu yüzden Session nesnesine ihtiyacımız yok ise bu özelliği pasif konuma getirmekte fayda vardır. Bazı durumlarda Session nesnesine sadece okuma amaçlı ihtiyaç duyabiliriz, bu durumda da Session nesnesine sadece okuma amaçlı erişeceğimizi sayfada bildirerek belli ölçüde performans kazanabiliriz.

Bir web formu için Session nesnesini pasif hale getirmek için yapmamız gereken tek şey Page direktifinden sonra aşağıdaki gibi EnableSessionState=”false” ifadesini yazmak.

<@Page EnableSessionState = “false”@>

Aynı şekilde Session nesnesini sadece okunabilir yapmak için için EnableSessionState = “ReadOnly” yazmak yeterli olacaktır.

6 – Gereksiz Postback İşlemleri

Bir web formunun ilk defa mı yoksa yeninden bir istek sonucu mu yüklendiğini anlamak için Page sınıfının IsPostBack özelliği kullanılmaktadır. Özellikle statik data bağlı kontrollerin bir web formunda kullanılması sırasında IsPostBack kontrolünü kullanıp sonraki yüklemelerde verilerin yeniden kontrollere bağlanmasını engellemeliyiz. Tabi bu durum için kontrole bağlı verinin statik olduğunu düşünüyoruz. Bu özelliğin örnek bir kullanımı biçimi aşapıdaki gibi olabilir.

private void OnPage_Load(…)
{
if(!Page.IsPostBack)
{
DataBagla();
}
}

7 – Dataları Application Nesnesinde Saklama

Bir çok veritabanı uygulamasında çok sık değişmeyen veriler dinamik bir şekilde her bir web formundan yüklenmektedir. Üstelik bu işlem her oturum için tekrar tekrar yapıldığı için sunucuya büyük bir yük bindirilmiş olur. Halbuki çok sık değişmeyen bu tip veriler global düzeyde bellekte saklanıp, her bir oturum bu veriye bu bellekteki nesneden erişirse hem web sunucusu büyük bir dertten kurtulacak hemde web formlarının istemciye yüklenmesi daha kısa süre alacaktır. Örneğin bu sitede yandaki kolonda bulunan dinamik menü tahmin edeceğiniz üzere veritabanından gelmektedir. Bu menü çok uzun bir süre aynı kalacağı için her bir kullanıcı siteye bağlandığında veritabanından bu menü listesini almak mantıklı değildir. Bu tarz durumlarda genellikle başka türlü bellekleme işlemleri yapılmasına rağmen bütün uygulama ve oturumlar için global düzeyde yönetilebilen Application nesneside kullanılabilir. Siteye herhangi bir bağlantı yapıldığında Menü bilgileri Application nesnesi yardımıyla belleğe alınır ve ardından bütün kullanıcılar zaten bellekte olan bu veriye erişirse sunucu büyük ölçüde rahatlayacaktır. Bu durum daha çok aynı siteye aynı anda çok fazla istemcinin bağlı olduğu durumlarda anlamlıdır.

Uygulama bazındaki değişkenleri Application nesnesi ile yönetebilmekteyiz. Örnekte verilen Menü bilgisini bir defaya mahsus olmak üzere belleğe yüklemek için gloabal.asax dosyasındaki Application_Start() metodunu kullanmamız yerinde olacaktır.

Yukarıdaki kullanıma bir örnek verelim :

//Global.asax dosyası

public void Application_Start()
{
SqlCommand cmd = new SqlCommand(“select * from Menu”,baglantinesnesi);
SqlDataAdapter adp = new SqlDataAdapter(cmd);
DataTable dtMenu = new DataTable(“MENU”);
adp.Fill(dtMenu);

Application[“MakaleMenu”] = dtMenu;
}

//Herhangi bir web formu
private void Page_Load()
{
DataTable menu = (DataTable)Application[“dtMenu”];
grdiMenu.DataSource = menu;
}

Not : Yukarıdaki örnekte global düzeydeki Application nesnesindeki bir elemanın değerinin ne şekilde elde edildiğine özellikle dikkat ediniz.

8 – Data Erişimini Optimize Etmek

Bir ASP.NET uygulamasının olmazsa olmaz bileşeni veritabanıdır. Veritabanları çok sık kullanıldığıdan veriye erişim tekniğini en optimum biçimde ayarlamamız çok önemlidir. Veri erişiminde eğer SQL Server kullanıyorsak derlenmiş veritabanı bileşenleri olan Stored Procedure kullanmak, sadece ileri yönlü ve okuma amaçlı veri erişimi yapıyorsak DataAdapter ve DataSet ikilisi yerine DataReader nesnelerini kullanmak, eğer varsa ilgili veri kaynağına özgü olan data erişim bileşenlerini(SqlDataReader,OracleDataReader vs.) kullanmak her zaman performansı olumlu yönde etkileyecektir.

9 – Ön Bellekleme (Caching) Yapmak

Ön bellekleme ASP.NET’in en önemli konularından birisidir. Ön bellekleme, bir HTML çıktısının yeniden sunucu tarafından oluşturulmaksızın daha önceki istekler sonucunda oluşturulmuş HTML çıktısını sunucunun belleğinde saklama ve gerektiğinde bellekteki hazır veriyi istemciye gönderme işlemine denir. ASP.NET, IIS sunucusunun ön bellekleme mekanizmasında da faydalanarak bir takım ön bellekleme mekanizmaları sunmaktadır. ASP.NET ön bellekleme konusu çok ayrıntılı ve üzerinde ayrıca çalışılması gereken bir konu olduğu için bu yazıda ön bellekleme konusunu ana hatlarıyla inceleyeceğim. Ön bellekleme işleminin performansı neden artırdığı açıkca ortada. Zira ASP.NET uygulamaları IIS sunucusunda açılan ’worker process’ ler sayesinde derlenip HTML çıktısına dönüştürülür. Derleme ve çıktıyı üretme işlemi zaman alan asıl bölüm olduğu için çok sık değişmeyen sayfaları bir ön bellek mekanizması ile her istekte bulunulduğunda yeniden dosya sisteminden okunmasını ve derlenmesini engellemeliyiz. Yine şu an bulunduğunuz siteden örnek verelim : Bu sitenin anasayfası gün içinde çok fazla değişmeyecektir. Dolayısıyla anasayfaya her istekte bulunan oturum için asp.net motorunu devreye sokmak hem sunucuyu yoracaktır hemde göreceli olarak sayfaların kullanıcı tarafından ulaşılması fazla zaman alacaktır. Bu durumda yapılması gereken bu sayfanın günlük olarak yada parametrik olarak ön belleklenmesidir.

ASP.NET üç tür ön bellekleme mekanizmasını destekler. Şimdi sırasıyla bu ön bellekleme mekanizmalarını inceleyeceğiz.

Output Caching(Çıktı ön bellekleme)

En basit tanımıyla “output caching”, bir sayfanın tümünün belli bir süre için yada bazı koşulların geçerliliği sağlanıncaya kadar sayfanın HTML formatında belleklenmesi ve gerektiğinde bu bilginin istemciye herhangi bir işlem yapılmadan gönderilmesidir. Bir sayfanın iki dakikalık süreyle ön belleklenmesi ve bu iki dakikadan sonra ön belleğin silinip çıktının yeniden üretilmesini sağlamak için aspx dosyalarında OutputCache direktifi aşağıdaki gibi kullanılır.

<%@OutputCache Duration = “120” VarByParam = “none”%>

Yukarıda, VaryByParam zorunlu bir parametre olmasına rağmen herhangi bir değer verilmemiştir. Ön bellekleme işlemi bu durumda iki dakikalık aralıklarla HTTP_User_Agent çevre değişkeninin değerine göre yapılmaktadır. Örneğin Internet Explorer tarayıcısı için ön belleğe alınmış bir HTML çıktısı, Netscape yada Opera gibi bir tarayıcda geçerli olmayabilir. Dolayısıyla sunucu ön bellekten okuma işlemini sadece aynı çıktıyı yorumlayabilecek tarayıcılar arasında gerçekleştirilecektir. Ön bellekleme işleminin etkisini anlamak için o anki saati ekrana yazan bir sayfa tasarlayın ve bu sayfanın OutputCache Duration özelliğini 10 yapıp programı çalıştırın. Eğer sadece her 10 saniyede bir saatin doğru olduğunu gözlemlerseniz ön bellekleme işlemini başarmışsınız demektir.

Bazı durumlarda sayfadaki ön bellekleme işlemini POST yada GET metoduyla sayfaya gelen herhangi bir değişkenin değerinin değişip değişmediğine göre de yapmak isteyebiliriz. Bu durumda yapmamız gereken ilgili değişkenleri ; karakteri ile ayırarak VaryByParam parametresi olarak değiştirmek. Örneğin sayfaya QueryString olarak gelen ID ve Login değişkenlerinin değişmesine göre ön bellekleme yapmak istiyorsak OutputCache direktifi aşağıdaki gibi kullanılmalıdır.

<%@OutputCache Duration = “120” VarByParam = “ID;Login”%>

OutputCatch direktifinin parametreleri bu kadarla sınırlı değildir. Örneğin VarybyHeader, VaryByCustom gibi kriterler de belirtmemiz mümkün. OutputCache direktifi ile ilgili ayrıntılı katalog bilgisi için MSDN yardım dökümanlarına başvurabilirsiniz.

Ön bellekleme performansı artıran bir faktör olmasına rağmen yanlış biçimde ve sonuçları tam olarak düşülmeden kullanıldığı takdirde aklımıza gelemeyecek problemlere neden olabilir. Bu yüzden istemcinin ön belleklenmiş veya yeniden üretilen veriyi alıp almaması arasındaki farkı iyi analiz etmek gerekir.

Fragment Caching(Kısmi ön bellekleme)

Bazı durumlarda sayfanın tümünü ön bellekleme yerine sayfada bulunan web kontrollerinin ön belleklenmesini isteyebiliriz. Özellikle header,footer, menu gibi kullanıcı kontrolü (user control) olabilecek bileşenler çok sık değişmediği için anasayfamıza ekleyeceğimiz bu tür kullanıcı kontrollerini ön beleğe alabilmekteyiz. Kullanıcı kontrolerinin ön belleğe alınma işlemi normal bir sayfanın ön belleğe alınma işleminden hiç bir farkı yoktur. Kullanıcı kontrollerini içeren .ascx sayfalarında OutputCaching direktifini kullanarak kullanıcı kontrolünün ön belleklenmesini sağlayabiliriz. Yine aynı şekilde VarByParam, Duration, VaryByHeader gibi parametreleri de kullanabilmekteyiz.

Data Caching(Veri ön bellekleme)

Daha önce performansı artırmanın yollarından birisinin bütün oturumların erişebileceği Application nesnesini kullanmak olduğunu söylemiştik. Ancak global düzeyde erişim sağlanabilen Application değişkeni ön bellekleme için özellştirilmemiş bir nesne modeli olduğu için kullanımı çok esnek değildir. ASP.NET yeni bir veri modeli ile data ön belleklemesi yapmaktadır. Bu veri modelini temsil eden değişken yine bütün oturumlar tarafından erişilebilen Caching değişkenidir. Caching değişkenin kullanımı tıpkı Application değişkeninin kullanımı gibidir. Örneğin bir DataSet nesnesini ön beleğe alıp diğer bütün oturumlar tarafından erişilebilmesine olanak sağlamak için aşağıdaki gibi ifade yazabiliriz.

DataSet ds = new DataSet();

Cach[“MENU”] = ds;

Aynı şekilde ön bellekteki DataSet nesnesini elde etmek için aşağıdaki satırı yazmamız yeterli olacaktır.

DataSet dsOnBellek = (DataSet)Cache[“MENU”];

Cache nesnesinin Application nesnesinden en önemli farkı ön bellekteki nesnelerin belleğin durumuna göre sunucu tarafından silinebileceğidir. Application değişkeninde böyle bir durum olduğu takdirde uygulama hatalı çalışabilecektir. Ancak Cache değişkeninde ilgili değişkene erişilmek istendiğinde eğer veri ön bellekte bulunamaz ise veri orjinal kaynağından tekrar alınabilmektedir. Bu durum hem belleğin efektif kullanımını sağlar hemde uygulamamızda herhangi bir hatanın meydana gelmsini önler.

Cache sınıfının Insert() metodu yardımıyla ilgili veri ön belleklemesinin ne zaman sonra ereceğini ve ön bellekleme işleminin hangi kriterlere göre yapılabileceğini de belirtmek mümkündür. Bu yazıda amacımız caching mekanizmasını tüm ayrıntılarıyla anlatmak olmadığı için caching ile ilgili ayrıntılı bilgi için MSDN’e başvurumanızı öneririm.

Sonuç

Bu yazıda en yüksek performansta çalışacak ASP.NET web uygulamaları geliştirmek için nelere dikkat etmemiz gerektiğini inceledik. Geliştirdiğiniz projelerde yularıda değindiğimiz dokuz maddeyi bir “check list” şeklinde kullanmanızı öneririm.

Makale:
ASP.NET Uygulamalarında Performansı Artırmak ASP.NET Sefer Algan
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: