Async CTP Güncellemesi : Daha verimli bir await

   Hatırlarsanız bir süre önce size Visual Studio Async CTP‘nin çıkışını duyurmuştum, tabi ki bunun bir topluluk teknik ön izleme olduğunun da altını çizerek. Teknik ön izlemeler  gelişmeleri yakından takip eden yazılım geliştiricilere gelecekte şekillenecek olan teknolojileri inceleme fırsatı vermekte; ama unutmamak gerekir ki kesinlikle ilgili teknolojinin son hali değillerdir. Async CTP’de tabi ki buna bir istisna değil ve yazılım geliştiricilerden gelen geri bildirimler sonrasında gelişmeye ve yenilenmeye devam etmekte. Bu yazımda async ctp güncellemesi sonrasında await’in nasıl daha verimli hale geldiğini paylaşıyor olacağım.

   Yakın zaman önce Visual Studio SP1’in çıkmasıyla async ctp kullanıcılar maalesef ki bu ön izlemeyi kullanamaz hale gelmişti. Bu durum ise yayınlanan bir tazeleme paketi ile düzeltilmişti. Bu tazeleme paketi pek çokları için kütüphanenin Visual Studio SP1 kütüphaneleri ile yeniden derlenmiş olan bir sürümü olarak düşünülse de aslında bu buz dağının sadece görünen yüzüydü. Gerçekte, beraberinden tasarımda da önemli güncellemeler yapıldı. Bu yazımda birlikte await içerisinde yapılan güncellemeyi inceliyor olacağız.

   Hatırlayacak olursanız Visual Studio Async CTP yazımda konunun pekişmesi için sizlerle aşağıdaki örnek kodu paylaşmıştım;

private async void adresleriBul_Click(object sender, EventArgs e) {
    var adress = "http://www.enterprisecoding.com/";
    var icerik = await new WebClient().DownloadStringTaskAsync(adress);
    var eslesimler = Regex.Matches(icerik,
                        @"(?<Protocol>\w+):\/\/(?<Domain>[\w@][\w.:@]+)\/?[\w\.?=%&=\-@/$,]*",
                        RegexOptions.IgnoreCase);

    foreach (Match eslesim in eslesimler) {
        adresListesi.Items.Add(eslesim.Value);
    }
}

   Bu kodun derlenmesi sonrasında ise aşağıdaki hale dönüşmüştü;

private void adresleriBul_Click(object sender, EventArgs e) {
    <adresleriBul_Click>d__0 d__ = new <adresleriBul_Click>d__0(0);
    d__.<>4__this = this;
    d__.sender = sender;
    d__.e = e;
    d__.MoveNextDelegate = new Action(d__.MoveNext);
    d__.$builder = VoidAsyncMethodBuilder.Create();
    d__.MoveNext();
}

[CompilerGenerated]
private sealed class <adresleriBul_Click>d__0 {
    private bool $__disposing;
    private bool $__doFinallyBodies;
    public VoidAsyncMethodBuilder $builder;
    private int <>1__state;
    public EventArgs <>3__e;
    public object <>3__sender;
    public AnaEkran <>4__this;
    private string <1>t__$await5;
    private TaskAwaiter<string> <a1>t__$await6;
    public string <adress>5__1;
    public Match <eslesim>5__4;
    public MatchCollection <eslesimler>5__3;
    public string <icerik>5__2;
    public EventArgs e;
    public Action MoveNextDelegate;
    public object sender;

    [DebuggerHidden]
    public <adresleriBul_Click>d__0(int <>1__state) {
        this.<>1__state = <>1__state;
    }

    [DebuggerHidden]
    public void Dispose() {
        this.$__disposing = true;
        this.MoveNext();
        this.<>1__state = -1;
    }

    public void MoveNext() {
        try {
            this.$__doFinallyBodies = true;
            if (this.<>1__state != 1) {
                if (this.<>1__state == -1) {
                    return;
                }

                this.<adress>5__1 = "http://www.enterprisecoding.com/";
                this.<a1>t__$await6 = new WebClient().DownloadStringTaskAsync(this.<adress>5__1).GetAwaiter<string>();
                this.<>1__state = 1;
                this.$__doFinallyBodies = false;
                if (this.<a1>t__$await6.BeginAwait(this.MoveNextDelegate)) {
                    return;
                }
                this.$__doFinallyBodies = true;
            }

            this.<>1__state = 0;
            this.<1>t__$await5 = this.<a1>t__$await6.EndAwait();
            this.<icerik>5__2 = this.<1>t__$await5;
            this.<eslesimler>5__3 = Regex.Matches(this.<icerik>5__2,
                           @"(?<Protocol>\w+):\/\/(?<Domain>[\w@][\w.:@]+)\/?[\w\.?=%&=\-@/$,]*",
   RegexOptions.IgnoreCase);
            IEnumerator CS$5$0002 = this.<eslesimler>5__3.GetEnumerator();
            try {
                while (CS$5$0002.MoveNext()) {
                    this.<eslesim>5__4 = (Match) CS$5$0002.Current;
                    this.<>4__this.adresListesi.Items.Add(this.<eslesim>5__4.Value);
                }
            }
            finally {
                if (this.$__doFinallyBodies) {
                    IDisposable CS$0$0003 = CS$5$0002 as IDisposable;
                    if (CS$0$0003 != null) {
                        CS$0$0003.Dispose();
                    }
                }
            }
            this.<>1__state = -1;
            this.$builder.SetCompleted();
        }
        catch (Exception) {
            this.<>1__state = -1;
            this.$builder.SetCompleted();
            throw;
        }
    }
}

    Async CTP güncellemesi sonrasında ise Async ekibi tarafından tasarımda yapılan bazı değişiklikler sonrasında artık karşımıza aşağıda gibi farklı bir kod çıkmakta;

private void adresleriBul_Click(object sender, EventArgs e)
{
    <adresleriBul_Click>d__0 d__ = new <adresleriBul_Click>d__0(0);
    d__.<>4__this = this;
    d__.sender = sender;
    d__.e = e;
    d__.<>t__MoveNextDelegate = new Action(d__.MoveNext);
    d__.$builder = AsyncVoidMethodBuilder.Create();
    d__.MoveNext();
}

[CompilerGenerated]
private sealed class <adresleriBul_Click>d__0
{
    // Fields
    private bool $__disposing;
    public AsyncVoidMethodBuilder $builder;
    private int <>1__state;
    public EventArgs <>3__e;
    public object <>3__sender;
    public MainForm <>4__this;
    public Action <>t__MoveNextDelegate;
    private TaskAwaiter<string> <a1>t__$await6;
    public string <adress>5__1;
    public Match <eslesim>5__4;
    public MatchCollection <eslesimler>5__3;
    public string <icerik>5__2;
    public EventArgs e;
    public object sender;

    // Methods
    [DebuggerHidden]
    public <adresleriBul_Click>d__0(int <>1__state)
    {
        this.<>1__state = <>1__state;
    }

    [DebuggerHidden]
    public void Dispose()
    {
        this.$__disposing = true;
        this.MoveNext();
        this.<>1__state = -1;
    }

    public void MoveNext()
    {
        try
        {
            string <1>t__$await5;
            bool $__doFinallyBodies = true;
            if (this.<>1__state != 1)
            {
                if (this.<>1__state != -1)
                {
                    this.<adress>5__1 = "http://www.enterprisecoding.com/";
                    this.<a1>t__$await6 = new WebClient().DownloadStringTaskAsync(this.<adress>5__1).GetAwaiter<string>();
                    if (this.<a1>t__$await6.IsCompleted)
                    {
                        goto Label_0089;
                    }
                    this.<>1__state = 1;
                    $__doFinallyBodies = false;
                    this.<a1>t__$await6.OnCompleted(this.<>t__MoveNextDelegate);
                }
                return;
            }
            this.<>1__state = 0;
        Label_0089:
            <1>t__$await5 = this.<a1>t__$await6.GetResult();
            this.<a1>t__$await6 = new TaskAwaiter<string>();
            this.<icerik>5__2 = <1>t__$await5;
            this.<eslesimler>5__3 = Regex.Matches(this.<icerik>5__2, @"(?<Protocol>\w+):\/\/(?<Domain>[\w@][\w.:@]+)\/?[\w\.?=%&=\-@/$,]*", RegexOptions.IgnoreCase);
            IEnumerator CS$5$0003 = this.<eslesimler>5__3.GetEnumerator();
            try
            {
                while (CS$5$0003.MoveNext())
                {
                    this.<eslesim>5__4 = (Match) CS$5$0003.Current;
                    this.<>4__this.adresListesi.Items.Add(this.<eslesim>5__4.Value);
                }
            }
            finally
            {
                if ($__doFinallyBodies)
                {
                    IDisposable CS$0$0004 = CS$5$0003 as IDisposable;
                    if (CS$0$0004 != null)
                    {
                        CS$0$0004.Dispose();
                    }
                }
            }
        }
        catch (Exception <>t__ex)
        {
            this.<>1__state = -1;
            this.$builder.SetException(<>t__ex);
            return;
        }
        this.<>1__state = -1;
        this.$builder.SetResult();
    }
}

   Daha detaya inecek olursak aşağıdaki iki kod parçacığını inceleyebiliriz. İlk sürümde oluşan kod;

if (this.<>1__state != 1) {
    if (this.<>1__state == -1) {
        return;
    }

    this.<adress>5__1 = "http://www.enterprisecoding.com/";
    this.<a1>t__$await6 = new WebClient().DownloadStringTaskAsync(this.<adress>5__1).GetAwaiter<string>();
    this.<>1__state = 1;
    this.$__doFinallyBodies = false;
    if (this.<a1>t__$await6.BeginAwait(this.MoveNextDelegate)) {
        return;
    }
    this.$__doFinallyBodies = true;
}

   Async CTP güncellemesi sonrasında oluşan kod;

if (this.<>1__state != 1){
    if (this.<>1__state != -1) {
        this.<adress>5__1 = "http://www.enterprisecoding.com/";
        this.<a1>t__$await6 = new WebClient().DownloadStringTaskAsync(this.<adress>5__1).GetAwaiter<string>();
        if (this.<a1>t__$await6.IsCompleted) {
            goto Label_0089;
        }
        this.<>1__state = 1;
        $__doFinallyBodies = false;
        this.<a1>t__$await6.OnCompleted(this.<>t__MoveNextDelegate);
    }
    return;
}

   Hmm, bu noktada kod satırları arasında kaybolmuş olabilirsiniz. İsterseniz oluşan her iki kodu da biraz sadeleştirelim.

İlk sürüm;

var geciciDegisken = yapilacakIslem.GetAwaiter();
// .....
// DURUMU SAKLA
// .....
if (geciciDegisken.BeginAwait(devami)){
    return;
}

devami:
// .....
// DURUMU GERI YUKLE
// .....
var sonuc = geciciDegisken.EndAwait();

Async CTP güncellemesi sonrası;

var geciciDegisken = yapilacakIslem.GetAwaiter();
if (!geciciDegisken.IsCompleted){
    // .....
    // DURUMU SAKLA
    // .....
    geciciDegisken.OnCompleted(devami);
    return;

    devami:
    // .....
    //DURUMU GERI YUKLE
    // .....
}
var sonuc = geciciDegisken.GetResult();
sonuc = null;

    Bu iki kod arasındaki temel farklık; yeni yöntemde artık nesnenin durumu saklanmadan önce verilen işin bitip bitmediği kontrol edilmesi. Örneğimizde yer alan web sayfasının indirilmesi işini düşünün; yavaş bir internet bağlantısında sürecin asenkron işlemesi en mantıklı olandır. Uygulama hızlı bir internet bağlantısında çalıştırıldığında ise sayfanın indirilme süresi göz ardı edilecek kadar kısa olacaktır; ki bu durumda ilk kod BeginAwait çağrısından çıkıldığında işlem sonlanmış olabilir fakat uygulama çoktan durum bilgisini saklamış olacaktır ve kodun devamında bu bilgiyi geri yükleyecektir. Bu sebeple üretilen kodun tasarımı güncellenmiş ve ikinci kodda görüldüğü gibi ilk önce sürecin tamamlanıp tamamlanmadığı kontrol edilmiştir. Üstelik güncelleme sonrasında artık delegate sadece gerektiği zaman oluşturularak heap işlemlerinden de kazanılan ekstra bir zaman söz konusudur.

    Bu yeni tasarımıyla Async CTP artık hızla sonlanan işlemler için neredeyse senkron olarak çalışacak ve nesnenin durum bilgisini saklamak/geri yüklemekle zaman kaybetmeyecek; işin uzun sürmesi durumunda ise standart hareket ederek sürecin asenkron çalışması sağlanacaktır. Yazılım geliştiriciler açısından bu yeni tasarım hayatı daha da kolaylaştıracak gibi görünüyor.

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