Uzak bir sunucuda herhangi bir işlem yapmanız gerektiğinde, programınız isteği oluşturur, gönderir ve ardından bir yanıt bekler. Örnek olarak SaveChanges()
ve kullanacağım SaveChangesAsync()
ama aynısı Find()
ve için de geçerli FindAsync()
.
myList
Veritabanınıza eklemeniz gereken 100'den fazla öğe listeniz olduğunu varsayalım. Bunu eklemek için, işleviniz şuna benzer:
using(var context = new MyEDM())
{
context.MyTable.AddRange(myList);
context.SaveChanges();
}
Önce bir örneğini oluşturursunuz MyEDM
, listeyi myList
tabloya eklersiniz MyTable
, ardından SaveChanges()
değişiklikleri veritabanında sürdürmek için çağırırsınız . İstediğiniz gibi çalışır, kayıtlar işlenir, ancak programınız kesinleştirme bitene kadar başka bir şey yapamaz. Bu, ne taahhüt ettiğinize bağlı olarak uzun zaman alabilir. Kayıtlarda değişiklik yapıyorsanız, kuruluş bunları teker teker işlemelidir (bir kez kaydetmiştim, güncellemeler için 2 dakika ayırın)!
Bu sorunu çözmek için iki şeyden birini yapabilirsiniz. İlki, eki işlemek için yeni bir diş açabilirsiniz. Bu, çalıştırmaya devam etmek için çağıran iş parçacığını serbest bırakacak olsa da, orada oturup bekleyecek yeni bir iş parçacığı oluşturdunuz. Bu ek yüke gerek yoktur ve async await
modelin çözdüğü şey budur .
I / O işlemleri için, await
çabucak en iyi arkadaşınız olur. Kod bölümünü yukarıdan alarak, şu şekilde değiştirebiliriz:
using(var context = new MyEDM())
{
Console.WriteLine("Save Starting");
context.MyTable.AddRange(myList);
await context.SaveChangesAsync();
Console.WriteLine("Save Complete");
}
Bu çok küçük bir değişikliktir, ancak kodunuzun verimliliği ve performansı üzerinde derin etkileri vardır. Peki ne olur? Kodun başlangıcı size bir örneğini oluşturmak, aynı MyEDM
ve eklemek myList
To MyTable
. Ancak aradığınızda await context.SaveChangesAsync()
, kodun yürütülmesi çağıran işleve geri döner! Böylece, tüm bu kayıtların işlenmesini beklerken, kodunuz çalışmaya devam edebilir. Yukarıdaki kodu içeren işlevin imzasına sahip olduğunu public async Task SaveRecords(List<MyTable> saveList)
varsayalım, çağıran işlev şöyle görünebilir:
public async Task MyCallingFunction()
{
Console.WriteLine("Function Starting");
Task saveTask = SaveRecords(GenerateNewRecords());
for(int i = 0; i < 1000; i++){
Console.WriteLine("Continuing to execute!");
}
await saveTask;
Console.Log("Function Complete");
}
Neden böyle bir işleve sahip olurdunuz bilmiyorum ama çıkardığı şey nasıl async await
çalıştığını gösteriyor . İlk önce ne olduğunu gözden geçirelim.
Yürütme girer MyCallingFunction
, Function Starting
ardından Save Starting
konsola yazılır, ardından işlev SaveChangesAsync()
çağrılır. Bu noktada, yürütme MyCallingFunction
1000 defaya kadar 'Yürütmeye Devam Ediyor' yazan for döngüsüne döner ve girer. Bittiğinde SaveChangesAsync()
, yürütme konsola SaveRecords
yazarak işleve döner Save Complete
. Her şey SaveRecords
tamamlandığında, yürütme tamamlandığında MyCallingFunction
olduğu gibi devam edecek SaveChangesAsync()
. Şaşkın? İşte bir örnek çıktı:
İşlev Başlangıcı
Başlangıcı Kaydet
Yürütmeye devam ediyor!
Yürütmeye devam ediyor!
Yürütmeye devam ediyor!
Yürütmeye devam ediyor!
Yürütmeye devam ediyor!
....
Yürütmeye devam ediyor!
Kaydetme Tamamlandı!
Yürütmeye devam ediyor!
Yürütmeye devam ediyor!
Yürütmeye devam ediyor!
....
Yürütmeye devam ediyor!
İşlev Tamamlandı!
Ya da belki:
İşlev Başlangıcı
Başlangıcı Kaydet
Yürütmeye devam ediyor!
Yürütmeye devam ediyor!
Kaydetme Tamamlandı!
Yürütmeye devam ediyor!
Yürütmeye devam ediyor!
Yürütmeye devam ediyor!
....
Yürütmeye devam ediyor!
İşlev Tamamlandı!
İşin güzelliği bu async await
, bir şeyin bitmesini beklerken kodunuz çalışmaya devam edebilir. Gerçekte, arama işleviniz olarak şuna benzer bir işleve sahip olursunuz:
public async Task MyCallingFunction()
{
List<Task> myTasks = new List<Task>();
myTasks.Add(SaveRecords(GenerateNewRecords()));
myTasks.Add(SaveRecords2(GenerateNewRecords2()));
myTasks.Add(SaveRecords3(GenerateNewRecords3()));
myTasks.Add(SaveRecords4(GenerateNewRecords4()));
await Task.WhenAll(myTasks.ToArray());
}
Burada, aynı anda giden dört farklı kaydetme kayıt fonksiyonuna sahipsiniz . işlevlerin seri olarak çağrılmasına göre MyCallingFunction
çok daha hızlı tamamlanır .async await
SaveRecords
Henüz değinmediğim tek şey await
anahtar kelime. Bunun yaptığı şey Task
, beklediğiniz şey tamamlanana kadar mevcut işlevin yürütülmesini durdurmaktır . Yani orijinal durumunda , fonksiyon bitene kadar MyCallingFunction
satır Function Complete
konsola yazılmayacaktır SaveRecords
.
Uzun lafın kısası, kullanma seçeneğiniz varsa async await
, uygulamanızın performansını büyük ölçüde artıracağı için yapmalısınız.