16 Aralık 2019 Pazartesi

Tek Başına await

Giriş
await Task tipinden sonuç döndüren asenkron bir işin bitmesini bekle olarak düşünülebilir.
await olmadan asenkron işin Result alanına erişmek doğru değil.Yani bu yazıdaki amaç aslında sanki Java'daki Future.get() metodunu beklemek gibi düşünülebilir.

Örnek
Şöyle yaparız.
Task ThisMethodWillThrow() { // note that this is **not** "async", but is awaitable
  ...
}
Örnek
Elimizde şöyle bir kod olsun
// Define other methods, classes and namespaces here
public async Task<string> Task1()
{
    await Task.Delay(5000);
    return "Task1 ready";
}   

public async Task<string> Task2()
{
    await Task.Delay(5000);
    return "Task2 ready";
}

public async Task<string> Task3()
{
    await Task.Delay(5000);
    return "Task3 ready";
}
Çağırmak için şöyle yaparız.
Stopwatch sw = new Stopwatch();

// Variant 1. Burada Task1()'in bitmesi beklendikten sonra Task2 başlatılıyor
sw.Start();
var m1 = await Task1();
var m2 = await Task2();
var m3 = await Task3();
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);

// Variant 2. Burada tüm işler paralel başlatılıyor
sw.Restart();
var t1 = Task1();
var t2 = Task2();
var t3 = Task3();
await t1;
await t2;
await t3;
sw.Stop();
Örnek
İkisinin farkını MSDN şöyle bir örnekle gösteriyor.
async Task<int> AccessTheWebAsync()
{ 
  HttpClient client = new HttpClient();
  Task<string> getStringTask = client.GetStringAsync("http://...");

  DoIndependentWork();

  string urlContents = await getStringTask;

  return urlContents.Length;
}
Tek başına kullanılmasının açıklaması şöyle.
If AccessTheWebAsync doesn't have any work that it can do between calling GetStringAsync and awaiting its completion, you can simplify your code by calling and awaiting in the following single statement.
Yani DoIndenpendentWork() metoduna ihtiyaç yoksa sadece şöyle yaparız.
string urlContents = await client.GetStringAsync();
Örnek
pull based ve push based iki işin farkı gibi de düşünülebilir. pull based tost için şöyle yaparız.
// I want some toast.  I will pull it out of the toaster when it is done.
// I will do nothing until the toast is available.
Toast t = toaster.MakeToast();
t.AddJam();
// Yum.
push based tost için şöyle yaparız.
// I want some toast.  But it might take a while and I can do more work
// while I am waiting:
Task<Toast> task = toaster.MakeToastAsync();
Toast t = await task;
// await returns to the caller if the toast is not ready, and assigns
// a callback. When the toast is ready, the callback causes this method
// to start again from this point:
t.AddJam();
// Yum.
Örnek
Elimizde şöyle bir kod olsun.
var user = await _userRepo.GetByUsername(User.Identity.Name);

//Some minor work that doesn't rely on the user object

user = await _userRepo.UpdateLastAccessed(user, DateTime.Now);

return user;
GetByUserName paralel çalışırken ana kod  devam etsin istersek şöyle yaparız.
var userTask = _userRepo.GetByUsername(User.Identity.Name);    
//Some work that doesn't rely on the user object    
user = await _userRepo.UpdateLastAccessed(await userTask, DateTime.Now);    
return user;
userTask'ı await ile beklemek gerekir. Şu kod yanlış çünkü userTask'ın Result alanına eriştiğimizde henüz bitmemiş olabilir.
var userTask = _userRepo.GetByUsername(User.Identity.Name);

//Some work that doesn't rely on the user object

user = await _userRepo.UpdateLastAccessed(userTask.Result, DateTime.Now);

return user;

Hiç yorum yok:

Yorum Gönder