Async ve await ile asenkron programlamaAsynchronous programming with async and await

Görev zaman uyumsuz programlama modeli (TAP) , zaman uyumsuz kod üzerinde bir soyutlama sağlar.The Task asynchronous programming model (TAP) provides an abstraction over asynchronous code. Her zaman olduğu gibi, kodu deyimler dizisi olarak yazarsınız.You write code as a sequence of statements, just like always. Bu kodu, bir sonraki başlamadan önce her bir deyimin tamamlansa da okuyabilirsiniz.You can read that code as though each statement completes before the next begins. Derleyici birçok dönüşüm gerçekleştirir, çünkü bu deyimlerden bazıları işe başlayabilir ve Task devam eden çalışmayı temsil eden bir döndürür.The compiler performs many transformations because some of those statements may start work and return a Task that represents the ongoing work.

Bu sözdiziminin amacı: bir deyim dizisi gibi okuyan kodu etkinleştirin, ancak dış kaynak ayırmaya ve görevler tamamlandığında çok daha karmaşık bir sırayla yürütülür.That's the goal of this syntax: enable code that reads like a sequence of statements, but executes in a much more complicated order based on external resource allocation and when tasks complete. Kullanıcıların zaman uyumsuz görevler içeren işlemlere yönelik yönergeler verme yöntemi benzerdir.It's analogous to how people give instructions for processes that include asynchronous tasks. Bu makalede, async ve await anahtar kelimelerin, bir dizi zaman uyumsuz yönergeler içeren kod hakkında neden daha kolay olduğunu görmek için bir yönergeler örneği kullanacaksınız.Throughout this article, you'll use an example of instructions for making a breakfast to see how the async and await keywords make it easier to reason about code, that includes a series of asynchronous instructions. Daha hızlı nasıl yapılacağını açıklamak için aşağıdaki listeye benzer yönergeler yazın:You'd write the instructions something like the following list to explain how to make a breakfast:

  1. Kahve kupa dök.Pour a cup of coffee.
  2. Bir Pan, sonra da iki Yumura kadar bir kaydır.Heat up a pan, then fry two eggs.
  3. Bacon üç dilimi.Fry three slices of bacon.
  4. İki adet içerik.Toast two pieces of bread.
  5. Bildirim 'e alın ve sıkıştı ekleyin.Add butter and jam to the toast.
  6. Turuncu bir büyütece bir cam dök.Pour a glass of orange juice.

Pişirme deneyiminiz varsa, bu yönergeleri zaman uyumsuz olarak yürütebilirsiniz.If you have experience with cooking, you'd execute those instructions asynchronously. Yumurlar için kaydırmayı ısıncak ve sonra Bacon 'u başlatacak.You'd start warming the pan for eggs, then start the bacon. Ekseyi Toaster ' a yerleştirip yumurtalar ' ı başlatın.You'd put the bread in the toaster, then start the eggs. İşlemin her adımında bir görev başlatır, sonra ilgilenmeniz için uygun olan görevlere dikkat etmeniz gerekir.At each step of the process, you'd start a task, then turn your attention to tasks that are ready for your attention.

Pişirme kahileri, paralel olmayan bir zaman uyumsuz çalışmaya yönelik iyi bir örnektir.Cooking breakfast is a good example of asynchronous work that isn't parallel. Bir kişi (veya iş parçacığı), tüm bu görevleri işleyebilir.One person (or thread) can handle all these tasks. Breakfast benzerleme vurguladı devam ederken bir kişi, ilk tamamlanmadan önce sonraki görevi başlatarak zaman uyumsuz olarak zaman uyumsuz hale getirebilirsiniz.Continuing the breakfast analogy, one person can make breakfast asynchronously by starting the next task before the first completes. Pişirme işlemi, birisinin onu izliyor olup olmadığı konusunda ilerler.The cooking progresses whether or not someone is watching it. Yumurlar için kaydırma işlemini başlattığınızda, Bacon kızartma başlayabilirsiniz.As soon as you start warming the pan for the eggs, you can begin frying the bacon. Bacon başladıktan sonra, ekseyi Toaster 'a yerleştirebilirsiniz.Once the bacon starts, you can put the bread into the toaster.

Paralel bir algoritma için birden çok ortak iş (veya iş parçacığı) gerekir.For a parallel algorithm, you'd need multiple cooks (or threads). Bunlardan biri, bir, Bacon, vb. olur.One would make the eggs, one the bacon, and so on. Her biri yalnızca bir göreve odaklanılmıştır.Each one would be focused on just that one task. Her bir Cook (veya iş parçacığı), Bacon 'un çevrilmeye hazırlanması veya bildirim açılanması için zaman uyumlu olarak engelleniyor.Each cook (or thread) would be blocked synchronously waiting for bacon to be ready to flip, or the toast to pop.

Şimdi C# deyimleri olarak yazılmış yönergeleri göz önünde bulundurun:Now, consider those same instructions written as C# statements:

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 Breakfast

Zaman uyumlu olarak hazırlanan kahhızlı, toplam her bir görevin toplamı olduğundan, yaklaşık olarak 30 dakika sürer.The synchronously prepared breakfast, took roughly 30 minutes because the total is the sum of each individual task.

Not

Coffee,, Egg , Bacon Toast Ve Juice sınıfları boş.The Coffee, Egg, Bacon, Toast, and Juice classes are empty. Bunlar yalnızca tanıtım amaçlı sınıflardır, hiçbir özellik içermez ve başka bir amaç sunabilir.They are simply marker classes for the purpose of demonstration, contain no properties, and serve no other purpose.

Bilgisayarlar bu yönergeleri insanlar ile aynı şekilde yorumlamaz.Computers don't interpret those instructions the same way people do. Bir sonraki ifadeye geçmeden önce, bilgisayar her bir bildirimde, iş tamamlanana kadar engeller.The computer will block on each statement until the work is complete before moving on to the next statement. Bu, karşılanunan bir Breakfast oluşturur.That creates an unsatisfying breakfast. Daha sonraki görevler, önceki görevler tamamlanana kadar başlatılamaz.The later tasks wouldn't be started until the earlier tasks had completed. Daha uzun sürer ve bazı öğeler sunulmadan önce soğuk hale gelir.It would take much longer to create the breakfast, and some items would have gotten cold before being served.

Bilgisayarın yukarıdaki yönergeleri zaman uyumsuz olarak yürütmesini istiyorsanız, zaman uyumsuz kod yazmanız gerekir.If you want the computer to execute the above instructions asynchronously, you must write asynchronous code.

Bu sorunlar, bugün yazdığınız programlar için önemlidir.These concerns are important for the programs you write today. İstemci programları yazdığınızda, kullanıcı ARABIRIMININ Kullanıcı girişine yanıt vermesini istersiniz.When you write client programs, you want the UI to be responsive to user input. Uygulamanız, Web 'den veri indirirken bir telefonu dondurulmuş hale döndürmemelidir.Your application shouldn't make a phone appear frozen while it's downloading data from the web. Sunucu programları yazdığınızda, iş parçacıklarının engellenmesini istemezsiniz.When you write server programs, you don't want threads blocked. Bu iş parçacıkları diğer isteklere hizmet verebilir.Those threads could be serving other requests. Zaman uyumsuz alternatifler mevcut olduğunda zaman uyumlu kod kullanarak daha ucuz bir şekilde ölçeklendirme imkanına sahip olabilirsiniz.Using synchronous code when asynchronous alternatives exist hurts your ability to scale out less expensively. Engellenen bu iş parçacıkları için ödeme yaparsınız.You pay for those blocked threads.

Başarılı modern uygulamalar zaman uyumsuz kod gerektirir.Successful modern applications require asynchronous code. Dil desteği olmadan, zaman uyumsuz kod gerekli geri çağırmaları, tamamlanma olaylarını veya başka bir deyişle, kodun orijinal hedefini görünmez hale gelir.Without language support, writing asynchronous code required callbacks, completion events, or other means that obscured the original intent of the code. Zaman uyumlu kodun avantajı, adım adım eylemlerin taranması ve anlaşılması kolay hale gelir.The advantage of the synchronous code is that its step-by-step actions make it easy to scan and understand. Geleneksel zaman uyumsuz modeller kodun temel eylemlerine değil, kodun zaman uyumsuz yapısına odaklanmaya zorlanır.Traditional asynchronous models forced you to focus on the asynchronous nature of the code, not on the fundamental actions of the code.

Engelleme, yerine awaitDon't block, await instead

Yukarıdaki kodda kötü bir uygulama gösterilmektedir: zaman uyumsuz işlemleri gerçekleştirmek için zaman uyumlu kod oluşturma.The preceding code demonstrates a bad practice: constructing synchronous code to perform asynchronous operations. Yazıldığı gibi, bu kod başka herhangi bir işi yapmadan yürüten iş parçacığını engeller.As written, this code blocks the thread executing it from doing any other work. Görevlerden herhangi biri devam ederken bu işlem kesintiye uğramaz.It won't be interrupted while any of the tasks are in progress. Bu, ' ın içine yerleştirdikten sonra Toaster ' ta başmış gibi olacaktır.It would be as though you stared at the toaster after putting the bread in. Bildirim alınana kadar sizi konuşuyor olan herkesi yoksayabilirsiniz.You'd ignore anyone talking to you until the toast popped.

İş parçacığı, görevler çalışırken engellenmemesi için bu kodu güncelleyerek başlayalım.Let's start by updating this code so that the thread doesn't block while tasks are running. awaitAnahtar sözcüğü, bir görevi başlatmak için engellenmeyen bir yöntem sağlar ve ardından bu görev tamamlandığında yürütmeye devam eder.The await keyword provides a non-blocking way to start a task, then continue execution when that task completes. Bir Breakfast kodu oluştur 'un basit bir zaman uyumsuz sürümü aşağıdaki kod parçacığına benzer:A simple asynchronous version of the make a breakfast code would look like the following snippet:

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.The total elapsed time is roughly the same as the initial synchronous version. Kod, zaman uyumsuz programlama için bazı temel özelliklerden yararlanmıştır.The code has yet to take advantage of some of the key features of asynchronous programming.

İpucu

, Ve ' nin tüm ve sırasıyla,, ve ' ın bir bütün olarak, ve ' ı FryEggsAsync FryBaconAsync ToastBreadAsync döndürecek şekilde güncelleştirilmiştir Task<Egg> Task<Bacon> Task<Toast> .The method bodies of the FryEggsAsync, FryBaconAsync, and ToastBreadAsync have all been updated to return Task<Egg>, Task<Bacon>, and Task<Toast> respectively. Yöntemler özgün sürümlerinden "Async" sonekini içerecek şekilde yeniden adlandırılır.The methods are renamed from their original version to include the "Async" suffix. Uygulamaları, bu makalenin ilerleyen bölümlerinde son sürümün bir parçası olarak gösterilir.Their implementations are shown as part of the final version later in this article.

Bu kod, yumurtalar veya Bacon pişirirken engellenmez.This code doesn't block while the eggs or the bacon are cooking. Bu kod, diğer görevleri de başlatmayacaktır.This code won't start any other tasks though. Yine de bildirim, siz de bir araya gelene kadar Toaster 'a yerleştirirsiniz.You'd still put the toast in the toaster and stare at it until it pops. Ancak en azından, ilgilenmeniz istenen herkese yanıt verirsiniz.But at least, you'd respond to anyone that wanted your attention. Birden çok siparişin yerleştirildiği bir restoran içinde, ilk pişirme sırasında Cook bir daha hızlı başlatılabilir.In a restaurant where multiple orders are placed, the cook could start another breakfast while the first is cooking.

Şimdi, henüz bitmemiş olan herhangi bir başlatılan görevi beklerken, Kahvalı üzerinde çalışan iş parçacığı engellenmiyor.Now, the thread working on the breakfast isn't blocked while awaiting any started task that hasn't yet finished. Bazı uygulamalarda, bu değişiklik gereklidir.For some applications, this change is all that's needed. Yalnızca bu değişikliğe sahip bir GUI uygulaması kullanıcıya yanıt veriyor.A GUI application still responds to the user with just this change. Ancak, bu senaryo için daha fazla bilgi istersiniz.However, for this scenario, you want more. Her bileşen görevinin her ardışık olarak yürütülmesini istemezsiniz.You don't want each of the component tasks to be executed sequentially. Önceki görevin tamamlanmasını beklerken önce her bir bileşen görevinin başlatılması daha iyidir.It's better to start each of the component tasks before awaiting the previous task's completion.

Görevleri eşzamanlı olarak BaşlatStart tasks concurrently

Birçok senaryoda, birkaç bağımsız görevi hemen başlatmak istersiniz.In many scenarios, you want to start several independent tasks immediately. Ardından, her bir görev tamamlandığında, daha önce hazırlanmaya devam edebilirsiniz.Then, as each task finishes, you can continue other work that's ready. Kahhızlı benzerleme vurguladı, daha hızlı bir şekilde daha hızlı bir şekilde daha hızlı bir şekilde yapılır.In the breakfast analogy, that's how you get breakfast done more quickly. Her şeyin aynı anda kapatılmasını de sağlar.You also get everything done close to the same time. Sık erişimli bir kahvaltı alacaksınız.You'll get a hot breakfast.

System.Threading.Tasks.TaskVe ilgili türler, sürmekte olan görevlerle ilgili nedenlerle kullanabileceğiniz sınıflardır.The System.Threading.Tasks.Task and related types are classes you can use to reason about tasks that are in progress. Bu sayede, aslında daha iyi bir şekilde daha çok benzeyen bir kod yazmanızı sağlar.That enables you to write code that more closely resembles the way you'd actually create breakfast. Eggs, Bacon ve bildirim ' ı aynı anda aşalım.You'd start cooking the eggs, bacon, and toast at the same time. Her biri bir eylem gerektirdiğinden, bu göreve dikkat etmeniz, sonraki eylemi ele almanız ve daha sonra ilgilenmeniz gereken başka bir şey için await ' ı kapatmanız gerekir.As each requires action, you'd turn your attention to that task, take care of the next action, then await for something else that requires your attention.

Bir görevi başlatır ve Task işi temsil eden nesneyi basılı tutabilirsiniz.You start a task and hold on to the Task object that represents the work. awaitSonucuyla çalışmadan önce her görevi gerçekleştirirsiniz.You'll await each task before working with its result.

Bu değişiklikleri Breakfast kodunda yapalim.Let's make these changes to the breakfast code. İlk adım, işlemler için görevleri her zaman beklerken depolamak yerine depolarlar:The first step is to store the tasks for operations when they start, rather than awaiting them:

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, bir sonraki await ve yumurg deyimlerini, Breakfast sunmadan önce yönteminin sonuna taşıyabilirsiniz:Next, you can move the await statements for the bacon and eggs to the end of the method, before serving breakfast:

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 Breakfast

Zaman uyumsuz hazırlanmış Breakfast yaklaşık 20 dakika sürdü, bu süre tasarrufları, bazı görevlerin eşzamanlı olarak çalıştırılmesidir.The asynchronously prepared breakfast took roughly 20 minutes, this time savings is because some tasks ran concurrently.

Yukarıdaki kod daha iyi çalışmaktadır.The preceding code works better. Tüm zaman uyumsuz görevleri aynı anda başlatabilirsiniz.You start all the asynchronous tasks at once. Her bir görevi yalnızca sonuçlara ihtiyacınız olduğunda bekleolursunuz.You await each task only when you need the results. Yukarıdaki kod, farklı mikro hizmetlere istek yapan bir Web uygulamasındaki koda benzer ve sonuçları tek bir sayfada birleştirir.The preceding code may be similar to code in a web application that makes requests of different microservices, then combines the results into a single page. Tüm istekleri hemen, ardından await Tüm bu görevleri ve Web sayfasını oluşturduğunuz şekilde yaparsınız.You'll make all the requests immediately, then await all those tasks and compose the web page.

Görevlerle oluşturmaComposition with tasks

Bildirim hariç her şeyi aynı anda kah, daha hızlı bir şekilde hazırlayın.You have everything ready for breakfast at the same time except the toast. Bildirim, zaman uyumsuz bir işlemin (Ekleyici) ve zaman uyumlu işlemlerin (alın ve sıkışan) bir bileşim haline getirilmesi.Making the toast is the composition of an asynchronous operation (toasting the bread), and synchronous operations (adding the butter and the jam). Bu kodun güncelleştirilmesi önemli bir kavramı gösterir:Updating this code illustrates an important concept:

Önemli

Zaman uyumsuz bir işlemin ardından zaman uyumlu iş tarafından oluşturulması zaman uyumsuz bir işlemdir.The composition of an asynchronous operation followed by synchronous work is an asynchronous operation. Başka bir şekilde ifade edilen bir işlemin herhangi bir bölümü zaman uyumsuz ise, tüm işlem zaman uyumsuzdur.Stated another way, if any portion of an operation is asynchronous, the entire operation is asynchronous.

Yukarıdaki kod, Task Task<TResult> çalışan görevleri tutmak için veya nesneleri kullanacağınızı gösterdi.The preceding code showed you that you can use Task or Task<TResult> objects to hold running tasks. awaitSonucunu kullanmadan önce her görevi gerçekleştirebilirsiniz.You await each task before using its result. Sonraki adım, diğer çalışmanın birleşimini temsil eden yöntemler oluşturmaktır.The next step is to create methods that represent the combination of other work. Kahvileri sunmadan önce, Butter ve sıkışmadan önce Ekleyici 'yi temsil eden görevi beklemek istersiniz.Before serving breakfast, you want to await the task that represents toasting the bread before adding butter and jam. Bu işi aşağıdaki kodla temsil edebilirsiniz:You can represent that work with the following code:

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.The preceding method has the async modifier in its signature. Bu yöntemin bir ifade içerdiğini derleyiciye bildirir await ; zaman uyumsuz işlemler içerir.That signals to the compiler that this method contains an await statement; it contains asynchronous operations. Bu yöntem, Ekleyici ve sıkışıklığı ekleyen görevi temsil eder.This method represents the task that toasts the bread, then adds butter and jam. Bu yöntem, bu Task<TResult> üç işlemin oluşumunu temsil eden bir döndürür.This method returns a Task<TResult> that represents the composition of those three operations. Kodun ana bloğu şu şekilde olur:The main block of code now becomes:

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.The previous change illustrated an important technique for working with asynchronous code. İşlemleri bir görevi döndüren yeni bir yönteme ayırarak görevleri oluşturursunuz.You compose tasks by separating the operations into a new method that returns a task. Bu görevin ne zaman bekleme seçeneğini belirleyebilirsiniz.You can choose when to await that task. Diğer görevleri eşzamanlı olarak başlatabilirsiniz.You can start other tasks concurrently.

Zaman uyumsuz özel durumlarAsynchronous exceptions

Bu noktaya kadar, tüm bu görevlerin başarıyla tamamlandığını açıkça kabul edersiniz.Up to this point, you've implicitly assumed that all these tasks complete successfully. Zaman uyumsuz yöntemler, zaman uyumlu karşılıkları gibi özel durumlar oluşturur.Asynchronous methods throw exceptions, just like their synchronous counterparts. Ö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.Asynchronous support for exceptions and error handling strives for the same goals as asynchronous support in general: You should write code that reads like a series of synchronous statements. Görevler, başarıyla tamamlanamazlar özel durumlar oluşturur.Tasks throw exceptions when they can't complete successfully. İstemci kodu, başlatılan bir görev olduğunda bu özel durumları yakalayabilir awaited .The client code can catch those exceptions when a started task is awaited. Örneğin, bildirim yaparken Toaster 'ın ateşlenmesini varsayalım.For example, let's assume that the toaster catches fire while making the toast. ToastBreadAsyncYöntemini aşağıdaki kodla eşleşecek şekilde değiştirerek benzetimini yapabilirsiniz:You can simulate that by modifying the ToastBreadAsync method to match the following code:

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.You'll get a warning when you compile the preceding code regarding unreachable code. Bu bilerek yapılan bir işlem, Toaster catch ateşine bir kez devam etmeyecektir.That's intentional, because once the toaster catches fire, operations won't proceed normally.

Bu değişiklikleri yaptıktan sonra uygulamayı çalıştırın ve aşağıdaki metne benzer bir çıkış yapmanız gerekir:Run the application after making these changes, and you'll output similar to the following text:

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.Notice that there's quite a few tasks completing between when the toaster catches fire and the exception is observed. Zaman uyumsuz olarak çalışan bir görev özel durum oluşturduğunda, bu görev hata verdi.When a task that runs asynchronously throws an exception, that Task is faulted. Görev nesnesi, özelliğinde oluşturulan özel durumu barındırır Task.Exception .The Task object holds the exception thrown in the Task.Exception property. Hatalı görevler bekledikleri zaman bir özel durum oluşturur.Faulted tasks throw an exception when they're awaited.

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ı.There are two important mechanisms to understand: how an exception is stored in a faulted task, and how an exception is unpackaged and rethrown when code awaits a faulted task.

Zaman uyumsuz olarak çalıştırılan kod bir özel durum oluşturduğunda, bu özel durum içinde depolanır Task .When code running asynchronously throws an exception, that exception is stored in the Task. Task.Exception System.AggregateException Zaman uyumsuz çalışma sırasında birden fazla özel durum oluşabileceğinden özellik bir özelliktir.The Task.Exception property is an System.AggregateException because more than one exception may be thrown during asynchronous work. Oluşturulan herhangi bir özel durum koleksiyona eklenir AggregateException.InnerExceptions .Any exception thrown is added to the AggregateException.InnerExceptions collection. Bu Exception özellik null ise, yeni bir AggregateException oluşturulur ve oluşturulan özel durum koleksiyondaki ilk öğedir.If that Exception property is null, a new AggregateException is created and the thrown exception is the first item in the collection.

Hatalı bir görev için en yaygın senaryo, Exception özelliğin tam olarak bir özel durum içermesine yöneliktir.The most common scenario for a faulted task is that the Exception property contains exactly one exception. awaitsHatalı bir görevi kodunuzda, koleksiyondaki ilk özel durum AggregateException.InnerExceptions yeniden oluşturulur.When code awaits a faulted task, the first exception in the AggregateException.InnerExceptions collection is rethrown. Bu nedenle, bu örnekteki çıktının bir yerine bir gösterilmektedir InvalidOperationException AggregateException .That's why the output from this example shows an InvalidOperationException instead of an 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.Extracting the first inner exception makes working with asynchronous methods as similar as possible to working with their synchronous counterparts. ExceptionSenaryonuz birden çok özel durum oluşturabileceği zaman kodunuzda özelliği inceleyebilirsiniz.You can examine the Exception property in your code when your scenario may generate multiple exceptions.

Devam etmeden önce, bu iki satırı yönteminizin içine ekleyin ToastBreadAsync .Before going on, comment out these two lines in your ToastBreadAsync method. Başka bir yangın başlatmak istemezsiniz:You don't want to start another fire:

Console.WriteLine("Fire! Toast is ruined!");
throw new InvalidOperationException("The toaster is on fire");

Görevleri verimli olarak awaitAwait tasks efficiently

awaitÖnceki kodun sonundaki deyim dizileri, sınıfının yöntemleri kullanılarak artırılabilir Task .The series of await statements at the end of the preceding code can be improved by using methods of the Task class. 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.One of those APIs is WhenAll, which returns a Task that completes when all the tasks in its argument list have completed, as shown in the following code:

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.Another option is to use WhenAny, which returns a Task<Task> that completes when any of its arguments completes. Döndürülen görevi, zaten bitdiğinin farkında olacak şekilde beklede olursunuz.You can await the returned task, knowing that it has already finished. Aşağıdaki kod, WhenAny ilk görevin bitmesini beklemek için nasıl kullanabileceğinizi gösterir ve sonra sonucunu işleyebilir.The following code shows how you could use WhenAny to await the first task to finish and then process its result. 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 .After processing the result from the completed task, you remove that completed task from the list of tasks passed to 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: After all those changes, the final version of the code looks like this:

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();
        }
    }
}

herhangi bir zaman uyumsuz Breakfast

Zaman uyumsuz hazırlanmış Breakfast 'in son sürümü yaklaşık 15 dakika sürdü, çü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 gerçekleştirmektedir.The final version of the asynchronously prepared breakfast took roughly 15 minutes because some tasks ran concurrently, and the code monitored multiple tasks at once and only take action when it was needed.

Bu son kod zaman uyumsuzdur.This final code is asynchronous. Bu, bir kişinin ne kadar hızlı bir şekilde bir kahtacağını daha doğru yansıtır.It more accurately reflects how a person would cook a breakfast. Yukarıdaki kodu, bu makaledeki ilk kod örneğiyle karşılaştırın.Compare the preceding code with the first code sample in this article. Temel eylemler, kodu okumayı hala temizler.The core actions are still clear from reading the code. Bu kodu, bu makalenin başlangıcında bir daha hızlı hale getirmek için bu talimatları okuduğunuzdan aynı şekilde okuyabilirsiniz.You can read this code the same way you'd read those instructions for making a breakfast at the beginning of this article. İç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.The language features for async and await provide the translation every person makes to follow those written instructions: start tasks as you can and don't block waiting for tasks to complete.

Sonraki adımlarNext steps