dynamic : statik ve dinamik diller arası köprü

Bir önceki makaleme gelen güzel yorumlar sonrası dynamic hakkında ikinci bir makale ile konuyu detaylandırmanın faydalı olacağını düşündüm.

C# 4.0’la birlikte gelen özellikleri inceleyenlerin dynamic hakkında düştüğü ortak bir yanılğı, dynamic’in CLR seviyesinde desteklendiğidir. Her ne kadar dynamic hayatımızda önemli bir değişikliğe neden olsa da, bu yanılgıya düşenler için basit kullanımlarda beklediklerinin aksine uygulamalarında performans kayıplarına neden olacaktır.

dynamic, CLR açısından bakıldığında, herhangi bir C# kütüphanesinden farklı değildir. Tabi ki microsoft bu kütüphanenin bizler tarafından daha kolay kullanılabilmesi amacıyla C# diline ekleme yapmış, derleyici desteği sağlamıştır.

Konuyu daha netleştirebilmek için bir önceki makalemde verdiğim aşağıdaki dynamic kod örneğini hatırlayalım:

class Program {
   static void Main(string[] args) {
      dynamic nesne = 1;

      if (nesne.GetType() == typeof(int)){
         Console.WriteLine("Tabi ki türü int");
      }  else {
         Console.WriteLine("Tüm makale hatalıymış :P");
      }

      nesne = nesne + 1;
   }
}

Bu örneğin derlenmesi sonrası oluşan kodu reflector ile incelersek karşımıza aşağıdaki gibi bir kod çıkacaktır:

internal class Program {
    private static void Main(string[] args) {
        object nesne = 1;
        if (o__SiteContainer0.<>p__Site1 == null) {
            o__SiteContainer0.<>p__Site1 = CallSite>.Create(Binder.UnaryOperation(CSharpBinderFlags.None, ExpressionType.IsTrue, typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));
        }
        if (o__SiteContainer0.<>p__Site2 == null) {
            o__SiteContainer0.<>p__Site2 = CallSite>.Create(Binder.BinaryOperation(CSharpBinderFlags.None, ExpressionType.Equal, typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null) }));
        }
        if (o__SiteContainer0.<>p__Site3 == null) {
            o__SiteContainer0.<>p__Site3 = CallSite>.Create(Binder.InvokeMember(CSharpBinderFlags.None, "GetType", null, typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));
        }
        if (o__SiteContainer0.<>p__Site1.Target.Invoke(o__SiteContainer0.<>p__Site1, o__SiteContainer0.<>p__Site2.Target.Invoke(o__SiteContainer0.<>p__Site2, o__SiteContainer0.<>p__Site3.Target.Invoke(o__SiteContainer0.<>p__Site3, nesne), typeof(int)))) {
            Console.WriteLine("Tabi ki t\x00fcr\x00fc int");
        }
        else {
            Console.WriteLine("T\x00fcm makale hatalıymış :P");
        }

        if (o__SiteContainer0.<>p__Site4 == null) {
            o__SiteContainer0.<>p__Site4 = CallSite>.Create(Binder.BinaryOperation(CSharpBinderFlags.None, ExpressionType.Add, typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null) }));
        }
        nesne = o__SiteContainer0.<>p__Site4.Target.Invoke(o__SiteContainer0.<>p__Site4, nesne, 1);
    }

    [CompilerGenerated]
    private static class o__SiteContainer0 {
        public static CallSite> <>p__Site1;
        public static CallSite> <>p__Site2;
        public static CallSite> <>p__Site3;
        public static CallSite> <>p__Site4;
    }
}

Görüldüğü gibi yazmış olduğumuz kod içerisine derleyici tarafında oldukça fazla müdahale edilmiş. Yapılan bu müdahale ile birlikte ortaya çıkan bu kodu, basit bir tür dönüşümü ile hızlıca ilerleyeceğimiz aşağıdaki gibi bir kod ile karşılaştırdığımızda hangisinin daha performanslı olacağı aşikar;

class Program {
   static void Main(string[] args) {
      object nesne = 1;

      if (nesne.GetType() == typeof(int)){
         Console.WriteLine("Tabi ki türü int");
      }  else {
         Console.WriteLine("Tüm makale hatalıymış :P");
      }

      nesne = (int)nesne + 1;
   }
}

Tabi ki bu karşılaştırma hiç bir zaman dynamic kullanmayın demek değil; fakat doğru yerde kullanın demek 😉

 

Peki dynamic kullanımı için doğru yer neresidir?

.Net 4.0 DLR (Dynamic Language Runtime, Dinamik Dil Çalışma-Zamanı) ve birlikte gelen dynamic anahtar kelimesi, statik diller (C#, Visual Basic v.b.) ile dinamik diller (Python, Ruby v.b.) arasında bir köprü olmaktadır.

CLR-DLR etkileşimi

Üstelik bu köprü sadece Python ve Ruby dilleriyle de sınırlı olmayıp; Javascript, Silverlight, Ofis/COM ve diğer pek çoklarını da kapsamaktadır.

.Net 4.0 öncesinde dinamik diller ve COM ile iletişim kurmakta yaşadığımız pek çok zorluk DLR ile birlikte tarih olacak gibi görünüyor. Bu noktalardaki dynamic kullanımı gerek geliştirme süresini hızlandırmada, gerekse de kod okunurluğunu arttırmada önemli bir katma değer sağlayacaktır.

Dinamil Dil Çalışma-Zamanı (DLR) nasıl çalışır?

Yazımın başında da belirttiğim gibi CLR bakış açısıyla DLR sadece bir kütüphanedir; fakat hayatımızdan önemli bir yer tutacak bir kütüphane 🙂

Dinamik dil çalışma-zamanı hakkında daha önce de araştırma yaptıysanız aşağıdaki grafik size tanıdık gelecektir.

dlr2

Statik dillerle dinamik diller arasında bir köprü olan DLR bu grafikte de görüldüğü gibi 4 ana parçadan oluşur:

  1. İfade ağacları (Expression Trees) : İfade ağaçları, Linq ile derinlemesine uğraşanlarınıza tanıdık gelecektir. Yazdığınız ifade, derleyici tarafından MSIL’e dönüştürülmek yerine programsal olarak işlenebilmesi amacıyla ifadeyi anlatan ağaç yapısında nesnelere dönüştürülecektir. Bu dönüşüm sayesinde, çalışacak kodun derlenme-zamanı oluşması nedeniyle statik dillerde sahip olamadığımız esnekliği kazanmaktayız.
  2. Dinamik Dağıtıcı (Dynamic Dispatch) :  En basit ifadeyle dinamik dağıtıcı, çalışma-zamanı metot ve özellik çağrılarına izin veren yapıdır. Dinamik bir tür üzerinde yapılan işlemler dinamik dağıtıcıya yönlendirilmekte, burada yapılmış olan işleme ait ifade ağacı yorumlanmaktadır. Dinamik dağıtıcı sayesinde C# içerisinden dinamik dillere çağrı yapılabilmesi sağlandığı gibi, aynı zamanda dinamik dillerden C# sınıflarına çağrı yapılabilmesine olanak sağlanmıştır. Bu sayede, çift yönlü olarak, her iki yaklaşımın güçlü yönleri aynı anda kullanılabilmektedir. Bir C# sınıfında dinamik dağıtıcı özelliğine sahip olabilmek için sınıfı IDynamicMetaObjectProvider, DynamicMetaObject, DynamicObject ve ExpandoObject gibi arayüz ve sınıflardan türetmek yeterli olacaktır.
  3. Call Site Önbelleği (Call Site Caching)  : Call Site, dinamik türler üzerinden aritmetik işlemler, metot çağrıları gibi çeşitli işlemleri yapabilmenizi sağlayan yerdir. Dinamik dil çalışma-zamanı üzerinde çalıştığı sınıflar ve işlemler hakkındaki bilgileri önbelleğe alarak ardıl çağrılarda bu bilgileri yeniden elde etmek yerine önbellekteki bilgilerden yararlanır. Bu yöntem sayesinde dynamic işlemler reflection yöntemiyle yapılanlarla kıyaslandığında daha hızlı gerçekleşir.
  4. Başlayıcılar (Binders) : Call site’lar içerisinde yer alan ve dinamik dil çalışma-zamanınca kullanılan bağlayıcılar işlemin gerçekleştirileceği .Net framework’ü, COM, silverlight, dinamik diller gibi ortamlarla iletişimi sağlarlar.

Yukarıdaki bilgiler ışığında, yazdığınız bir dinamik kod DLR tarafından öncelikle daha önceden işlenip işlenmediğinin anlaşılması amacıyla önbellekte kontrol edilir. Eğer aynı işlem daha önce çağrıldıysa önbellekte yer alan temsilci (delegate) üzerinden hazırda bulunan adımlarla işlevini yerine getirir. Eğer dinamik kod ilk defa işleniyorsa ifade ağacı ilgili call site’a iletilerek arkaplanda yer alan bağlayıcı yardımıyla çalıştırılır ve sonraki kullanımlarda kullanılmak üzere bir temsilci atanarak önbelleğe alınır.

Yukarıda anlattıklarımdan sonra heyecanlanmamak mümkün değil bence. Şimdiye kadar işlemlerimizi statik olarak gerçekleştirdiğimiz C#, Visual Basic gibi dillere dinamik olarak çalışma-zamanında işlem yapabilme yeteneği eklenmesi kayda değer bir yenilik.

Fatih Boy

Ankara'da yaşayan Fatih, bir kamu kurumunda danışman olarak çalışmaktadır. ALM süreçleri, kurumsal veri yolu sistemleri, kurumsal altyapı ve yazılım geliştirme konularında destek vermektedir. Boş zamanlarında açık kaynak kodlu projeler geliştirmeyi ve bilgisini yazdığı makalelerle paylaşmayı seven Fatih, aynı zamanda Visual C# ve Visual Studio teknolojileri konusundan Microsoft tarafından altı yıl üst üste MVP (En Değerli Profesyonel) ödülüne layık görülmüştür. İş hayatı boyunca masaüstü uygulamaları, web teknolojileri, akıllı istemciler gibi konularda Asp.Net, Php, C#, Java programlama dilleri ve MySql, MsSql ve Oracle gibi veritabanı yönetim yazılımları ile çalışmıştır. İngilizce ve Türkçe olarak yayınlanan makalelerini gerek İngilizce bloğunda, gerekse de Türkçe bloğunda bulabileceğiniz gibi web sitesinden de açık kaynak kodlu geliştirdiği yazılımlarına ulaşabilirsiniz. vCard - Twitter - Facebook - Google+

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir