Size özel sorularınızı aşağıda cevaplayacağım, ancak verimi nasıl tasarladığımız ve beklediğimizle ilgili kapsamlı makalelerimi okumanız iyi olur.
https://blogs.msdn.microsoft.com/ericlippert/tag/continuation-passing-style/
https://blogs.msdn.microsoft.com/ericlippert/tag/iterators/
https://blogs.msdn.microsoft.com/ericlippert/tag/async/
Bu makalelerin bazıları artık güncel değil; oluşturulan kod birçok yönden farklıdır. Ancak bunlar size kesinlikle nasıl çalıştığı konusunda fikir verecektir.
Ayrıca, lambdaların kapanış sınıfları olarak nasıl üretildiğini anlamıyorsanız, önce bunu anlayın . Lambdas'ınız yoksa, başları veya kuyrukları asenkron yapamazsınız.
Bir bekleme süresine ulaşıldığında, çalışma zamanı bundan sonra hangi kod parçasının çalıştırılması gerektiğini nasıl bilir?
await
şu şekilde oluşturulur:
if (the task is not completed)
assign a delegate which executes the remainder of the method as the continuation of the task
return to the caller
else
execute the remainder of the method now
Bu temelde bu. Beklemek sadece süslü bir dönüş.
Ne zaman kaldığı yerden devam edebileceğini nasıl biliyor ve nerede olduğunu nasıl hatırlıyor?
Eh, bunu nasıl yapacağım olmadan bekliyor? Foo yöntemi, yöntem çubuğunu çağırdığında, bir şekilde, çubuğun ne yaptığı önemli değil, foo'nun aktivasyonunun tüm yerelleri bozulmadan, foo'nun ortasına nasıl geri döneceğimizi hatırlıyoruz.
Assembler'da bunun nasıl yapıldığını biliyorsun. Foo için bir aktivasyon kaydı yığına itilir; yerlilerin değerlerini içerir. Çağrı noktasında, foo'daki dönüş adresi yığına itilir. Çubuk tamamlandığında, yığın işaretçisi ve komut işaretçisi olmaları gereken yere sıfırlanır ve foo, kaldığı yerden devam eder.
Beklemenin devamı tamamen aynıdır, tek fark, kaydın, etkinleştirme dizisinin bir yığın oluşturmaması gibi bariz bir nedenden ötürü yığına konulmasıdır .
Bekleyen delege, görevin devamı olarak (1) bir sonraki yürütmeniz gereken komut işaretçisini veren bir arama tablosunun girdisi olan bir sayı ve (2) yerellerin ve geçicilerin tüm değerlerini içerir.
Orada bazı ek donanımlar var; örneğin, .NET'te bir try bloğunun ortasına dalmak yasa dışıdır, bu nedenle kodun adresini bir try bloğunun içine tabloya yapıştıramazsınız. Ancak bunlar muhasebe detaylarıdır. Kavramsal olarak, aktivasyon kaydı basitçe yığına taşınır.
Mevcut çağrı yığınına ne oluyor, bir şekilde kaydediliyor mu?
Mevcut aktivasyon kaydındaki ilgili bilgiler asla ilk etapta yığına konulmaz; başlangıçtan itibaren yığın olarak tahsis edilir. (Biçimsel parametreler normalde yığına veya kayıtlara aktarılır ve daha sonra yöntem başladığında bir yığın konumuna kopyalanır.)
Arayanların aktivasyon kayıtları saklanmaz; Bekleme muhtemelen onlara geri dönecek, unutmayın, böylece normal şekilde ele alınacaktır.
Bunun, Scheme gibi dillerde gördüğünüz basitleştirilmiş devam ettirme bekleme stili ile güncel devamla arama yapıları arasındaki önemli bir fark olduğunu unutmayın. Bu dillerde, arayanlara geri devam etme dahil tüm devamlılık call-cc tarafından yakalanır .
Ya arama yöntemi beklemeden önce başka yöntem çağrıları yaparsa - neden yığının üzerine yazılmaz?
Bu yöntem çağrıları geri döner ve bu nedenle, etkinleştirme kayıtları bekleme noktasında artık yığın üzerinde değildir.
Ve bir istisna ve yığın çözülme durumunda çalışma zamanı tüm bunları nasıl halledebilir?
Yakalanmamış bir istisna durumunda, istisna yakalanır, görevin içinde saklanır ve görevin sonucu alındığında yeniden fırlatılır.
Daha önce bahsettiğim tüm muhasebe defterlerini hatırlıyor musun? İstisna anlambilimini doğru yapmak çok büyük bir acıydı, size söyleyeyim.
Verime ulaşıldığında, çalışma zamanı eşyaların nereden alınması gerektiğini nasıl takip ediyor? Yineleyici durumu nasıl korunur?
Aynı şekilde. Yerellerin durumu yığına taşınır ve bir MoveNext
sonraki çağrıldığında devam etmesi gereken talimatı temsil eden bir sayı yerellerle birlikte depolanır.
Ve yine, istisnaların doğru bir şekilde ele alındığından emin olmak için bir yineleyici bloğunda bir sürü dişli var.