2016-02-17 43 views
6

Bu, herhangi bir gerçek dünya sorununa kıyasla meraktan daha fazla talep edilir.Async özyineleme. Hafızam aslında nereye gidiyor?

Aşağıdaki kodu düşünün:

void Main() 
{ 
    FAsync().Wait(); 
} 

async Task FAsync() 
{ 
    await Task.Yield(); 
    await FAsync(); 
} 

senkron dünyada, bu sonuçta bir stackoverflow neden olur. zaman uyumsuz dünyasında

, bu basitçe tam da bu veri nedir (ben gevşek "asenkron yığını" diyebileceğimiz bir şey ile ilgilidir varsayıyorum?) çok fazla bellek

tüketir ve nasıl olduğunu düzenlenen?

cevap

12

İyi soru.

Yığın, devamı'un birleşimidir. Devam, basitçe, programın daha sonra ne yapacağına dair bilgi. Geleneksel olmayan uyumsuz bir ortamda, bu yığın üzerinde bir dönüş adresi olarak temsil edilir; Yöntem döndüğünde, yığına bakar ve dönüş adresine dönüşür. Yığın ayrıca, yerel değişkenlerin değerlerinin, devam ettirmenin başladığı noktada ne olduğu hakkında bilgi sahibi olur.

Eşzamansız bir durumda, tüm bu bilgiler yığınta depolanır. Bir görev, görev tamamlandığında çağrılan bir temsilci içerir. Temsilci, herhangi bir yerel değişken veya başka bir durum için alanlar içeren bir "kapatma" sınıfının örneğine bağlanır. Ve elbette görevlerin kendileri yığın nesnelerdir.

merak edebilirsiniz: o devam görev tamamlandığında çağrıldığında bir temsilci olduğu durum buysa, nasıl o zaman tamamlanmasıdır noktada çağrı yığını değil görevini tamamlar koddur idam? Görev, numaralı bir pencere mesajını göndererek devam ettirme delegesini çağırmayı seçebilir ve mesaj döngüsü mesajı işlediğinde, çağrıyı yapar. Bu nedenle çağrı, mesaj döngüsünün genellikle oturduğu yığının "üstünde" bulunur. (Devam etmek için kullanılan çağırma stratejisinin kesin ayrıntıları, görevin oluşturulduğu içeriğe göre değişir; ayrıntılar için paralel kitaplık görevine ilişkin daha gelişmiş bir kılavuza bakın.)

Tüm bunların nasıl olduğuna dair iyi bir giriş makalesi eserler burada bulabilirsiniz:

https://msdn.microsoft.com/en-us/magazine/hh456403.aspx

detayların bazıları değişti Mads makale ama fikirler sağlam olduğunu yazdı beri. (i3arnon'un cevabı bunun nasıl geliştiğini gösterir; Mads'in yazısında her şey yığın üzerinde gider, ancak bu bazı senaryolarda fazla miktarda çöp üretmeye başlar. Daha sofistike bir kodgen, bazı bilgileri yığında tutmamıza izin verir. Sürekliliklerin mantıksal olarak nasıl temsil edildiğini görmek için gereklidir.)

Programınızı almak ve oluşturulmuş tüm delegeleri ve görevleri ve bunların arasındaki referansları çizmek için eğlenceli ve aydınlatıcı bir çalışmadır. Bi dene!

+1

@ i3arnon: hah, monitörümde bu yazı tipinde rn ve m arasındaki farkı söylemek neredeyse imkansız! Orada bir an için düzeninizle kafam karışmıştı. :-) –

+0

sorunlu bir addır. Bir başkasıyla (I3arnon yani Barnon'a benzeyecek şekilde) yazıyordum ama insanlar bir L. – i3arnon

+1

@ i3arnon için yanlış yazıyordu: C# görüşmelerinin sonunda sormayı sevdiğim saçma bir bulmaca hatırlattı: ne 5432l + 12345' nedir? Düşündüğün gibi 66666 değil. Yazıyı doğru bir şekilde alırsanız bunun uzun bir edebi olduğunu söyleyemezsiniz. –

2

Derleyici, async yönteminizi bir durum makinesi yapısına dönüştürür. Yapı, öncelikle yığında oluşturulur. Tamamlanmamış bir görevi beklediğinizde (aksi halde eşzamanlı olarak çalışmaya devam eder ve yığının taşmasına neden olur) bu durum makinesi kutulanır ve yığına taşınır.Örneğin

bu yöntem:, çok fazla yığın depolanan her yineleme için durum kendini yineleme "geleneksel" olarak,

private struct <M>d__0 : IAsyncStateMachine 
{ 
    public int <>1__state; 
    public AsyncTaskMethodBuilder <>t__builder; 
    void IAsyncStateMachine.MoveNext() 
    { 
     try 
     { 
     } 
     catch (Exception exception) 
     { 
      this.<>1__state = -2; 
      this.<>t__builder.SetException(exception); 
      return; 
     } 
     this.<>1__state = -2; 
     this.<>t__builder.SetResult(); 
    } 
    [DebuggerHidden] 
    void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine) 
    { 
     this.<>t__builder.SetStateMachine(stateMachine); 
    } 
} 

Böylece:

public async Task M() 
{ 
} 

Bu durum makinesi dönüştü yinelemeler bu belleği taşabilir. Eşzamansız bir yöntemde durum yığında depolanır ve taşması da (genellikle daha büyük olsa da) taşabilir.