Async ve await ile asenkron programlama
Görev zaman uyumsuz programlama modeli (TAP), zaman uyumsuz kod üzerinde bir soyutlama sağlar. Her zaman olduğu gibi, kodu bir deyim dizisi olarak yazarsiniz. Bu kodu, sonraki başlamadan önce her deyim tamamlanacak gibi okuyabilirsiniz. Derleyici birçok dönüştürme gerçekleştirir çünkü bu deyimlerden bazıları çalışmaya başlayabilir ve devam eden işi Task temsil eden bir dönüş yapar.
Bu söz dizimlerinin amacı şudur: deyim dizisi gibi okunan, ancak dış kaynak ayırmaya ve görevler tamamlandığında çok daha karmaşık bir sırada yürütülen kodu etkinleştirin. Bu, insanların zaman uyumsuz görevleri içeren süreçler için yönergeler vermeleri ile benzerdir. Bu makale boyunca, ve anahtar sözcüklerinin bir dizi zaman uyumsuz yönergeleri içeren kod hakkında gerekçe göstermeyi nasıl kolaylaştıracaklarını görmek için bir yemek yapmak için bir yönergeler async await örneği kullanacaktır. Bir yemeğin nasıl hazır olacağını açıklamak için aşağıdaki listeye benzer bir yönergeler yazabilirsiniz:
- Bir fincan kahvenin içini doldur.
- Bir pan'ı ısıtır, sonra da iki tane yemek yer.
- Üç dilimli dilimle.
- İki parça ekmeğe tosla.
- Tağrıslık ve jam ekleyin.
- Bir su içerek portakal suyu.
Yemek konusunda deneyime sahip olursanız, bu yönergeleri zaman uyumsuz olarak yürütürsiniz. Yemek için pan'ı ısıtmaya, sonra da sosisi başlatmaya başlarsın. Tost makinesine ekin koymalı ve sonra da kahveyi başlatıyorsunuz. Sürecin her adımını bir görev başlatarak dikkat çekmenizi ve dikkat etmeye hazır görevlere çevirmeniz gerekir.
Yemek yemek, paralel olmayan zaman uyumsuz işlere iyi bir örnektir. Tek bir kişi (veya iş parçacığı) bu görevlerin hepsini işebilir. Aşağıdaki benzetmeye devam eden bir kişi, ilk görev tamamlandıktan sonra bir sonraki görevi başlatarak zaman uyumsuz olarak yemek hazırlar. Birisi izlese de izlemese de devam ediyor. Yemek için pan'ı ısıtmaya başlar başlamaz, meyveyi ısıtmaya başlayabilirsiniz. Başlatıcı başladıktan sonra, dilimi tost makinesine koyalım.
Paralel bir algoritma için birden çok yemek (veya iş parçacığı) gerekir. Bunlardan biri yalıtılmış, biri de sandviç gibi bir şey olur. Her biri yalnızca bu göreve odaklanan bir görevdir. Her yemek (veya iş parçacığı) zaman uyumlu bir şekilde atmaya hazır olmak için ya da atacak olan antıfı beklerken engellenmiş olur.
Şimdi, C# deyimleri ile yazılmış olan yönergelerin aynısını göz önünde bulundurarak:
using System;
using System.Threading.Tasks;
namespace AsyncBreakfast
{
class Program
{
static void Main(string[] args)
{
Coffee cup = PourCoffee();
Console.WriteLine("coffee is ready");
Egg eggs = FryEggs(2);
Console.WriteLine("eggs are ready");
Bacon bacon = FryBacon(3);
Console.WriteLine("bacon is ready");
Toast toast = ToastBread(2);
ApplyButter(toast);
ApplyJam(toast);
Console.WriteLine("toast is ready");
Juice oj = PourOJ();
Console.WriteLine("oj is ready");
Console.WriteLine("Breakfast is ready!");
}
private static Juice PourOJ()
{
Console.WriteLine("Pouring orange juice");
return new Juice();
}
private static void ApplyJam(Toast toast) =>
Console.WriteLine("Putting jam on the toast");
private static void ApplyButter(Toast toast) =>
Console.WriteLine("Putting butter on the toast");
private static Toast ToastBread(int slices)
{
for (int slice = 0; slice < slices; slice++)
{
Console.WriteLine("Putting a slice of bread in the toaster");
}
Console.WriteLine("Start toasting...");
Task.Delay(3000).Wait();
Console.WriteLine("Remove toast from toaster");
return new Toast();
}
private static Bacon FryBacon(int slices)
{
Console.WriteLine($"putting {slices} slices of bacon in the pan");
Console.WriteLine("cooking first side of bacon...");
Task.Delay(3000).Wait();
for (int slice = 0; slice < slices; slice++)
{
Console.WriteLine("flipping a slice of bacon");
}
Console.WriteLine("cooking the second side of bacon...");
Task.Delay(3000).Wait();
Console.WriteLine("Put bacon on plate");
return new Bacon();
}
private static Egg FryEggs(int howMany)
{
Console.WriteLine("Warming the egg pan...");
Task.Delay(3000).Wait();
Console.WriteLine($"cracking {howMany} eggs");
Console.WriteLine("cooking the eggs ...");
Task.Delay(3000).Wait();
Console.WriteLine("Put eggs on plate");
return new Egg();
}
private static Coffee PourCoffee()
{
Console.WriteLine("Pouring coffee");
return new Coffee();
}
}
}
Zaman uyumlu olarak hazırlanan yemek, her bir görevin toplamı olduğundan yaklaşık 30 dakika sürdü.
Not
Coffee, Egg , , ve Bacon sınıfları Toast Juice boştur. Bunlar yalnızca gösterim amaçlı işaretçi sınıflarıdır, özellik içermez ve başka bir amaca hizmet etmez.
Bilgisayarlar bu yönergeleri insanlarınki gibi yorumlamaz. Bilgisayar, bir sonraki deyime ilerlemeden önce iş tamamlandıktan sonra her deyimde engellenir. Bu da memnuniyetsiz bir yemek oluşturur. Sonraki görevler, önceki görevler tamamlanana kadar başlatılamz. Yemek oluşturmak çok daha uzun sürer ve bazı öğeler servise başlamadan önce üşüşmüş olur.
Bilgisayarın yukarıdaki yönergeleri zaman uyumsuz olarak yürütmesi için zaman uyumsuz kod yazmanız gerekir.
Bu endişeler, bugün yazacakları programlar için önemlidir. İstemci programları yazarken kullanıcı arabiriminin kullanıcı girişine yanıt vermesini istersiniz. Uygulamanız, web'den veri indirirken bir telefonun donmuş gibi görünmesine neden olmaması gerekir. Sunucu programları yazarken iş parçacıklarının engellenmiş olarak kabul ednsin. Bu iş parçacıkları başka isteklere hizmet ediyor olabilir. Zaman uyumsuz alternatifler olduğunda zaman uyumlu kodu kullanmak, ölçeği daha az maliyetli bir şekilde ölçeklendirme becerinizi zarara neden olur. Engellenen iş parçacıkları için ödeme siz ödersiniz.
Başarılı modern uygulamalar için zaman uyumsuz kod gerekir. Dil desteği olmadan, zaman uyumsuz kod yazmak için geri çağırmalar, tamamlama olayları veya kodun özgün amacını karartacak başka bir ifade gerekir. Zaman uyumlu kodun avantajı, adım adım eylemlerinin taramayı ve anlamayı kolaylaştırmadır. Geleneksel zaman uyumsuz modeller sizi kodun temel eylemlerine değil, zaman uyumsuz doğasına odaklanmaya zorlar.
Engelleme, bunun yerine await
Yukarıdaki kod kötü bir uygulama gösteriyor: zaman uyumsuz işlemler gerçekleştirmek için zaman uyumlu kod oluşturma. Yazıldığı gibi, bu kod onu yürüten iş parçacığının başka herhangi bir iş yapmalarını engeller. Görevlerden herhangi biri devam ederken kesintiye uğramaz. Bu, içine yer verdikten sonra tost makinesine bakmış gibi olur. Tedrilene kadar konuşanları yoksayabilirsiniz.
Görevler çalışırken iş parçacığının engellemesini engellemek için bu kodu güncelleştirerek başlayalım. anahtar sözcüğü, bir görevi başlatmak ve görev tamamlandığında yürütmeye await devam etmek için engelleyici olmayan bir yol sağlar. basit bir zaman uyumsuz sürümü bir kod kodu yapmak aşağıdaki kod parçacığı gibi olabilir:
static async Task Main(string[] args)
{
Coffee cup = PourCoffee();
Console.WriteLine("coffee is ready");
Egg eggs = await FryEggsAsync(2);
Console.WriteLine("eggs are ready");
Bacon bacon = await FryBaconAsync(3);
Console.WriteLine("bacon is ready");
Toast toast = await ToastBreadAsync(2);
ApplyButter(toast);
ApplyJam(toast);
Console.WriteLine("toast is ready");
Juice oj = PourOJ();
Console.WriteLine("oj is ready");
Console.WriteLine("Breakfast is ready!");
}
Önemli
Geçen toplam süre kabaca ilk zaman uyumlu sürümle aynıdır. Kod henüz zaman uyumsuz programlamanın bazı önemli özelliklerinden yararlanmamıştır.
İpucu
, ve yöntemlerinin FryEggsAsync FryBaconAsync ToastBreadAsync gövdeleri sırasıyla , ve Task<Egg> Task<Bacon> dönüşleri için Task<Toast> güncelleştirildi. Yöntemler özgün sürümünden "Async" soneki içerecek şekilde yeniden adlandırılır. Uygulamaları, bu makalenin sonraki kısımlarında son sürümün bir parçası olarak gösterilir.
Bu kod, tırslar veya sosisler tırstırma sırasında engellemez. Ancak bu kod başka görev başlatmaz. Yine de tost makinesine koyarak açılana kadar buna baktırıyor oluruz. Ancak en azından dikkat çekmek isteyen herkese yanıt verirsiniz. Birden çok siparişin bulunduğu bir restorana yemekçı, ilk sipariş sipariş edilirken başka bir yemek başlatabilirsiniz.
Şimdi, henüz bitmiş olan herhangi bir başlatan görevi beklerken, yemeğin üzerinde çalışan iş parçacığı engellenmiş değil. Bazı uygulamalar için tek gereken bu değişikliktir. Gui uygulaması kullanıcıya yalnızca bu değişiklikle yanıt verir. Ancak, bu senaryo için daha fazlasını istiyor. Bileşen görevlerinin her biri sırayla yürütülebilir. Önceki görevin tamamlanmasını bekleymeden önce bileşen görevlerinin her biri başlatmak daha iyidir.
Görevleri eşzamanlı olarak başlatma
Birçok senaryoda, birkaç bağımsız görevi hemen başlatmak istediğiniz senaryolar vardır. Ardından, her görev tamam olduğunda hazır olan diğer işlere devam edersiniz. Buna benzer bir benzetmede, daha hızlı bir şekilde yemek yemek için bu şekilde yapılır. Ayrıca her şeyi aynı anda tamamlarsiniz. Sıcak bir yemek yersiniz.
ve System.Threading.Tasks.Task ilgili türleri, devam eden görevleri gerekçe olarak kullanmak için kullanabileceğiniz sınıflardır. Bu sayede, gerçekten bir yemek oluşturma yönteme daha yakından benzeyen bir kod yazmanızı sağlar. Aynı anda yemek, yemek ve tost yapmaya başlarsın. Her biri eylem gerektirdiği için, dikkati bu göreve çevirir, sonraki eylemle ilgilenin ve ardından dikkat gerektiren başka bir şeyi beklersiniz.
Bir görevi başlatan ve işi temsil Task eden nesneyi tutar. Her görevi, await sonucuyla çalışmadan önce siz de gösterirsiniz.
Şimdi bu değişiklikleri kod koduna bakalım. İlk adım, görevleri başladıkları zaman, bunları beklerken depolamaktır:
Coffee cup = PourCoffee();
Console.WriteLine("Coffee is ready");
Task<Egg> eggsTask = FryEggsAsync(2);
Egg eggs = await eggsTask;
Console.WriteLine("Eggs are ready");
Task<Bacon> baconTask = FryBaconAsync(3);
Bacon bacon = await baconTask;
Console.WriteLine("Bacon is ready");
Task<Toast> toastTask = ToastBreadAsync(2);
Toast toast = await toastTask;
ApplyButter(toast);
ApplyJam(toast);
Console.WriteLine("Toast is ready");
Juice oj = PourOJ();
Console.WriteLine("Oj is ready");
Console.WriteLine("Breakfast is ready!");
Daha sonra, sandviçi servis etmeden önce yönteminin sonuna kadar olan ifadeleri await hareket ettirebilirsiniz:
Coffee cup = PourCoffee();
Console.WriteLine("Coffee is ready");
Task<Egg> eggsTask = FryEggsAsync(2);
Task<Bacon> baconTask = FryBaconAsync(3);
Task<Toast> toastTask = ToastBreadAsync(2);
Toast toast = await toastTask;
ApplyButter(toast);
ApplyJam(toast);
Console.WriteLine("Toast is ready");
Juice oj = PourOJ();
Console.WriteLine("Oj is ready");
Egg eggs = await eggsTask;
Console.WriteLine("Eggs are ready");
Bacon bacon = await baconTask;
Console.WriteLine("Bacon is ready");
Console.WriteLine("Breakfast is ready!");
Zaman uyumsuz olarak hazırlanmış olan yemek yaklaşık 20 dakika sürerken bu kez bazı görevlerin eşzamanlı olarak çalıştırılamı nedeniyle tasarruf sağlanmıştır.
Yukarıdaki kod daha iyi çalışır. Tüm zaman uyumsuz görevleri aynı anda başlatabilirsiniz. Her görevi yalnızca sonuçlara ihtiyacınız olduğunda beklersiniz. Yukarıdaki kod, farklı mikro hizmetlerden istekte bulunarak sonuçları tek bir sayfada birleştiren bir web uygulamasındaki koda benzer olabilir. Tüm istekleri hemen ve ardından tüm bu await görevleri yapacak ve web sayfasını oluşturabilirsiniz.
Görevlerle oluşturma
Bildirim hariç her şeyi aynı anda kah, daha hızlı bir şekilde hazırlayın. Bildirim, zaman uyumsuz bir işlemin (Ekleyici) ve zaman uyumlu işlemlerin (alın ve sıkışan) bir bileşim haline getirilmesi. Bu kodun güncelleştirilmesi önemli bir kavramı gösterir:
Önemli
Zaman uyumsuz bir işlemin ardından zaman uyumlu iş tarafından oluşturulması zaman uyumsuz bir işlemdir. Başka bir şekilde ifade edilen bir işlemin herhangi bir bölümü zaman uyumsuz ise, tüm işlem zaman uyumsuzdur.
Yukarıdaki kod, Task Task<TResult> çalışan görevleri tutmak için veya nesneleri kullanacağınızı gösterdi. awaitSonucunu kullanmadan önce her görevi gerçekleştirebilirsiniz. Sonraki adım, diğer çalışmanın birleşimini temsil eden yöntemler oluşturmaktır. Kahvileri sunmadan önce, Butter ve sıkışmadan önce Ekleyici 'yi temsil eden görevi beklemek istersiniz. Bu işi aşağıdaki kodla temsil edebilirsiniz:
static async Task<Toast> MakeToastWithButterAndJamAsync(int number)
{
var toast = await ToastBreadAsync(number);
ApplyButter(toast);
ApplyJam(toast);
return toast;
}
Önceki Yöntem async imzasında değiştiriciye sahiptir. Bu yöntemin bir ifade içerdiğini derleyiciye bildirir await ; zaman uyumsuz işlemler içerir. Bu yöntem, Ekleyici ve sıkışıklığı ekleyen görevi temsil eder. Bu yöntem, bu Task<TResult> üç işlemin oluşumunu temsil eden bir döndürür. Kodun ana bloğu şu şekilde olur:
static async Task Main(string[] args)
{
Coffee cup = PourCoffee();
Console.WriteLine("coffee is ready");
var eggsTask = FryEggsAsync(2);
var baconTask = FryBaconAsync(3);
var toastTask = MakeToastWithButterAndJamAsync(2);
var eggs = await eggsTask;
Console.WriteLine("eggs are ready");
var bacon = await baconTask;
Console.WriteLine("bacon is ready");
var toast = await toastTask;
Console.WriteLine("toast is ready");
Juice oj = PourOJ();
Console.WriteLine("oj is ready");
Console.WriteLine("Breakfast is ready!");
}
Önceki değişiklik, zaman uyumsuz kod ile çalışmak için önemli bir teknik gösterilmiştir. İşlemleri bir görevi döndüren yeni bir yönteme ayırarak görevleri oluşturursunuz. Bu görevin ne zaman bekleme seçeneğini belirleyebilirsiniz. Diğer görevleri eşzamanlı olarak başlatabilirsiniz.
Zaman uyumsuz özel durumlar
Bu noktaya kadar, tüm bu görevlerin başarıyla tamamlandığını açıkça kabul edersiniz. Zaman uyumsuz yöntemler, zaman uyumlu karşılıkları gibi özel durumlar oluşturur. Özel durumlar ve hata işleme için zaman uyumsuz destek genel olarak zaman uyumsuz destek ile aynı hedeflere sahiptir: bir dizi zaman uyumlu deyim gibi okuyan bir kod yazmalısınız. Görevler, başarıyla tamamlanamazlar özel durumlar oluşturur. İstemci kodu, başlatılan bir görev olduğunda bu özel durumları yakalayabilir awaited . Örneğin, bildirim yaparken Toaster 'ın ateşlenmesini varsayalım. ToastBreadAsyncYöntemini aşağıdaki kodla eşleşecek şekilde değiştirerek benzetimini yapabilirsiniz:
private static async Task<Toast> ToastBreadAsync(int slices)
{
for (int slice = 0; slice < slices; slice++)
{
Console.WriteLine("Putting a slice of bread in the toaster");
}
Console.WriteLine("Start toasting...");
await Task.Delay(2000);
Console.WriteLine("Fire! Toast is ruined!");
throw new InvalidOperationException("The toaster is on fire");
await Task.Delay(1000);
Console.WriteLine("Remove toast from toaster");
return new Toast();
}
Not
Erişilemeyen kodla ilgili yukarıdaki kodu derlerken bir uyarı alırsınız. Bu bilerek yapılan bir işlem, Toaster catch ateşine bir kez devam etmeyecektir.
Bu değişiklikleri yaptıktan sonra uygulamayı çalıştırın ve aşağıdaki metne benzer bir çıkış yapmanız gerekir:
Pouring coffee
Coffee is ready
Warming the egg pan...
putting 3 slices of bacon in the pan
Cooking first side of bacon...
Putting a slice of bread in the toaster
Putting a slice of bread in the toaster
Start toasting...
Fire! Toast is ruined!
Flipping a slice of bacon
Flipping a slice of bacon
Flipping a slice of bacon
Cooking the second side of bacon...
Cracking 2 eggs
Cooking the eggs ...
Put bacon on plate
Put eggs on plate
Eggs are ready
Bacon is ready
Unhandled exception. System.InvalidOperationException: The toaster is on fire
at AsyncBreakfast.Program.ToastBreadAsync(Int32 slices) in Program.cs:line 65
at AsyncBreakfast.Program.MakeToastWithButterAndJamAsync(Int32 number) in Program.cs:line 36
at AsyncBreakfast.Program.Main(String[] args) in Program.cs:line 24
at AsyncBreakfast.Program.<Main>(String[] args)
Toaster catch ateşlemesi ve özel durumun gözlemlendiği zaman arasında çok sayıda görevin tamamlandığına dikkat edin. Zaman uyumsuz olarak çalışan bir görev özel durum oluşturduğunda, bu görev hata verdi. Görev nesnesi, özelliğinde oluşturulan özel durumu barındırır Task.Exception . Hatalı görevler bekledikleri zaman bir özel durum oluşturur.
Anlaşılması gereken iki önemli mekanizma vardır: bir özel durumun hatalı görevde depolanması ve kodun hatalı bir görevi beklediği zaman bir özel durumun paketlenmesi ve yeniden oluşturulması.
Zaman uyumsuz olarak çalıştırılan kod bir özel durum oluşturduğunda, bu özel durum içinde depolanır Task . Task.Exception System.AggregateException Zaman uyumsuz çalışma sırasında birden fazla özel durum oluşabileceğinden özellik bir özelliktir. Oluşturulan herhangi bir özel durum koleksiyona eklenir AggregateException.InnerExceptions . Bu Exception özellik null ise, yeni bir AggregateException oluşturulur ve oluşturulan özel durum koleksiyondaki ilk öğedir.
Hatalı bir görev için en yaygın senaryo, Exception özelliğin tam olarak bir özel durum içermesine yöneliktir. awaitsHatalı bir görevi kodunuzda, koleksiyondaki ilk özel durum AggregateException.InnerExceptions yeniden oluşturulur. Bu nedenle, bu örnekteki çıktının bir yerine bir gösterilmektedir InvalidOperationException AggregateException . İlk iç özel durumun ayıklanması, zaman uyumsuz yöntemlerle zaman uyumlu karşılıklarıyla çalışmaya benzer şekilde çalışmayı sağlar. ExceptionSenaryonuz birden çok özel durum oluşturabileceği zaman kodunuzda özelliği inceleyebilirsiniz.
Devam etmeden önce, bu iki satırı yönteminizin içine ekleyin ToastBreadAsync . Başka bir yangın başlatmak istemezsiniz:
Console.WriteLine("Fire! Toast is ruined!");
throw new InvalidOperationException("The toaster is on fire");
Görevleri verimli olarak await
awaitÖnceki kodun sonundaki deyim dizileri, sınıfının yöntemleri kullanılarak artırılabilir Task . Bu API 'lerden biri, WhenAll Task aşağıdaki kodda gösterildiği gibi, bağımsız değişken listesindeki tüm görevler tamamlandığında tamamlanan bir döndürür.
await Task.WhenAll(eggsTask, baconTask, toastTask);
Console.WriteLine("Eggs are ready");
Console.WriteLine("Bacon is ready");
Console.WriteLine("Toast is ready");
Console.WriteLine("Breakfast is ready!");
Diğer bir seçenek de WhenAny , Task<Task> bağımsız değişkenlerinden herhangi biri tamamlandığında tamamlanan bir döndürür. Döndürülen görevi, zaten bitdiğinin farkında olacak şekilde beklede olursunuz. Aşağıdaki kod, WhenAny ilk görevin bitmesini beklemek için nasıl kullanabileceğinizi gösterir ve sonra sonucunu işleyebilir. Tamamlanan görevden elde edilen sonucu işledikten sonra, bu tamamlanmış görevi öğesine geçirilen görev listesinden kaldırırsınız WhenAny .
var breakfastTasks = new List<Task> { eggsTask, baconTask, toastTask };
while (breakfastTasks.Count > 0)
{
Task finishedTask = await Task.WhenAny(breakfastTasks);
if (finishedTask == eggsTask)
{
Console.WriteLine("Eggs are ready");
}
else if (finishedTask == baconTask)
{
Console.WriteLine("Bacon is ready");
}
else if (finishedTask == toastTask)
{
Console.WriteLine("Toast is ready");
}
breakfastTasks.Remove(finishedTask);
}
Tüm bu değişiklikler yapıldıktan sonra, kodun son sürümü şöyle görünür:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace AsyncBreakfast
{
class Program
{
static async Task Main(string[] args)
{
Coffee cup = PourCoffee();
Console.WriteLine("coffee is ready");
var eggsTask = FryEggsAsync(2);
var baconTask = FryBaconAsync(3);
var toastTask = MakeToastWithButterAndJamAsync(2);
var breakfastTasks = new List<Task> { eggsTask, baconTask, toastTask };
while (breakfastTasks.Count > 0)
{
Task finishedTask = await Task.WhenAny(breakfastTasks);
if (finishedTask == eggsTask)
{
Console.WriteLine("eggs are ready");
}
else if (finishedTask == baconTask)
{
Console.WriteLine("bacon is ready");
}
else if (finishedTask == toastTask)
{
Console.WriteLine("toast is ready");
}
breakfastTasks.Remove(finishedTask);
}
Juice oj = PourOJ();
Console.WriteLine("oj is ready");
Console.WriteLine("Breakfast is ready!");
}
static async Task<Toast> MakeToastWithButterAndJamAsync(int number)
{
var toast = await ToastBreadAsync(number);
ApplyButter(toast);
ApplyJam(toast);
return toast;
}
private static Juice PourOJ()
{
Console.WriteLine("Pouring orange juice");
return new Juice();
}
private static void ApplyJam(Toast toast) =>
Console.WriteLine("Putting jam on the toast");
private static void ApplyButter(Toast toast) =>
Console.WriteLine("Putting butter on the toast");
private static async Task<Toast> ToastBreadAsync(int slices)
{
for (int slice = 0; slice < slices; slice++)
{
Console.WriteLine("Putting a slice of bread in the toaster");
}
Console.WriteLine("Start toasting...");
await Task.Delay(3000);
Console.WriteLine("Remove toast from toaster");
return new Toast();
}
private static async Task<Bacon> FryBaconAsync(int slices)
{
Console.WriteLine($"putting {slices} slices of bacon in the pan");
Console.WriteLine("cooking first side of bacon...");
await Task.Delay(3000);
for (int slice = 0; slice < slices; slice++)
{
Console.WriteLine("flipping a slice of bacon");
}
Console.WriteLine("cooking the second side of bacon...");
await Task.Delay(3000);
Console.WriteLine("Put bacon on plate");
return new Bacon();
}
private static async Task<Egg> FryEggsAsync(int howMany)
{
Console.WriteLine("Warming the egg pan...");
await Task.Delay(3000);
Console.WriteLine($"cracking {howMany} eggs");
Console.WriteLine("cooking the eggs ...");
await Task.Delay(3000);
Console.WriteLine("Put eggs on plate");
return new Egg();
}
private static Coffee PourCoffee()
{
Console.WriteLine("Pouring coffee");
return new Coffee();
}
}
}
Zaman uyumsuz hazırlanmış Breakfast 'in son sürümü yaklaşık 15 dakika sürer, çünkü bazı görevler eşzamanlı olarak çalışır ve kod aynı anda birden çok görevi izlemiş ve yalnızca gerekli olduğunda işlem yaptı.
Bu son kod zaman uyumsuzdur. Bu, bir kişinin ne kadar hızlı bir şekilde bir kahtacağını daha doğru yansıtır. Yukarıdaki kodu, bu makaledeki ilk kod örneğiyle karşılaştırın. Temel eylemler, kodu okumayı hala temizler. Bu kodu, bu makalenin başlangıcında bir daha hızlı hale getirmek için bu talimatları okuduğunuzdan aynı şekilde okuyabilirsiniz. İçin dil özellikleri async ve await çeviri, her birinin bu yazılı yönergeleri izlemesini sağlar: Başlangıç görevleri, yaptığınız gibi başlatın ve görevlerin tamamlanmasını beklemeyi engellemez.