Karma bir şey mi? (örneğin, .NET programım bir zaman uyumsuz çağrıyı tamamlayana kadar bir yığın kullanıyor mu ve tamamlanıncaya kadar başka bir yapıya geçiyor, bu noktada yığının bir sonraki öğeden emin olabileceği bir duruma geri döndürülüyor? )
Temel olarak evet.
Varsayalım
async void MyButton_OnClick() { await Foo(); Bar(); }
async Task Foo() { await Task.Delay(123); Blah(); }
İşte devamların nasıl birleştirildiğine dair son derece basitleştirilmiş bir açıklama. Gerçek kod çok daha karmaşıktır, ancak bu fikri tersine çevirir.
Düğmesini tıklayın. Bir mesaj kuyruğa alındı. İleti döngüsü iletiyi işler ve ileti sırasının dönüş adresini yığına koyarak tıklama işleyicisini çağırır. Yani, işleyici yapıldıktan sonra olan şey , mesaj döngüsünün çalışmaya devam etmesi gerektiğidir. Dolayısıyla, işleyicinin devamı döngüdür.
Tıklama işleyici, Foo () öğesini çağırır ve dönüş adresini yığına yerleştirir. Yani, Foo'nun devamı tıklama işleyicinin geri kalan kısmıdır.
Foo, Task.Delay öğesini çağırır ve dönüş adresini yığına koyar.
Görev: Gecikme, bir Görevi hemen geri döndürmek için ne gerekiyorsa yapsın. Yığın attı ve biz de Foo'ya geri döndük.
Foo, döndürülen görevi tamamlayıp tamamlamadığını kontrol eder. O değil. Devamı ait beklemektedir Foo görevinin devamı olarak yukarı temsilci olduğunu Blah (çağıran bir temsilci) oluşturur ve işaretler, böylece) Blah (aramak. (Az önce yanlış bir açıklama yaptım; yakaladın mı? Değilse, bir an içinde ortaya koyacağız.)
Foo daha sonra kendi Görev nesnesini oluşturur, eksik olarak işaretler ve yığını tıklama işleyicisine döndürür.
Tıklama işleyici Foo'nun görevini inceler ve eksik olduğunu keşfeder. İşleyicideki beklemenin devamı Bar () öğesini çağırmaktır, bu nedenle tıklama işleyicisi Bar () öğesini çağıran ve onu Foo () tarafından döndürülen görevin devamı olarak ayarlayan bir temsilci oluşturur. Daha sonra yığını ileti döngüsüne döndürür.
Mesaj döngüsü mesajları işlemeye devam eder. Sonunda, gecikme görevi tarafından oluşturulan zamanlayıcı büyüsü işini yapar ve kuyruğa gecikme görevinin devamının yürütülebileceğini söyleyen bir mesaj gönderir. Bu yüzden mesaj döngüsü görev devamını çağırır ve kendisini her zamanki gibi yığının üzerine koyar. Bu delege Blah () diyor. Blah () yaptığı işi yapar ve yığını geri döndürür.
Şimdi ne olacak? İşte biraz zor. Gecikme görevinin devamı sadece Blah'ı () çağırmaz. Ayrıca Bar () çağrısını da tetiklemek zorundadır , ancak bu görev Bar'ı bilmiyor!
Foo aslında (1) Blah'ı () çağıran ve (2) Foo'nun yarattığı ve olay işleyicisine geri verdiği görevin devamını çağıran bir temsilci yarattı. Bar () diyen bir delege diyoruz.
Ve şimdi yapmamız gereken her şeyi doğru sırada yaptık. Ancak mesaj döngüsünde mesajları çok uzun süre işlemeyi hiç bırakmadık, bu yüzden uygulama duyarlı kaldı.
Bu senaryoların bir yığın için çok gelişmiş olması mükemmel bir anlam ifade eder, ancak yığının yerini ne alabilir?
Delegelerin kapanış sınıfları yoluyla birbirlerine referanslar içeren görev nesnelerinin grafiği. Bu kapatma sınıfları , en son idam edilenlerin konumunu ve yerlilerin değerlerini takip eden devlet makineleridir . Ayrıca, verilen örnekte, işletim sistemi tarafından uygulanan global durum eylem sırası ve bu eylemleri yürüten ileti döngüsü.
Alıştırma: Tüm bunların mesaj döngüleri olmayan bir dünyada nasıl çalıştığını düşünüyorsunuz? Örneğin, konsol uygulamaları. bir konsol uygulamasında beklemek oldukça farklı; nasıl çalıştığını şimdiye kadar bildiklerinizden çıkarabilir misiniz?
Bu yıllar önce öğrendiğimde, yığın şimşek hızlı ve hafif olduğu için oradaydı, eldeki görev için son derece verimli yönetimi desteklediği için yığıntan uygulamada ayrılmış bir bellek parçası (pun amaçlı?). Ne değişti?
Yığınlar, yöntem aktivasyonlarının ömürleri bir yığın oluşturduğunda yararlı bir veri yapısıdır, ancak benim örneğimde tıklama işleyicisinin, Foo, Bar ve Blah'ın aktivasyonları bir yığın oluşturmaz. Dolayısıyla bu iş akışını temsil eden veri yapısı bir yığın olamaz; bunun yerine, bir iş akışını temsil eden yığınlara ayrılmış görevlerin ve temsilcilerin bir grafiğidir. Beklenenler, iş akışında, daha önce başlatılan iş tamamlanana kadar iş akışında daha fazla ilerleme kaydedilemeyen noktalardır; biz beklerken, tamamlanan belirli görevlere bağlı olmayan diğer işleri yürütebiliriz .
Yığın, yalnızca karelerden oluşan bir dizidir; burada kareler, işlevlerin ortasına (çağrının gerçekleştiği yer) işaretçiler (()) ve yerel değişkenlerin ve temps değerlerini içerir. Görevlerin devamı aynı şeydir: temsilci işleve bir göstericidir ve işlevin ortasında (beklemenin gerçekleştiği yerde) belirli bir noktaya başvuran bir duruma sahiptir ve kapanışın her yerel değişken veya geçici için alanları vardır . Çerçeveler artık güzel ve düzgün bir dizi oluşturmuyor, ancak tüm bilgiler aynı.