13 Eylül 2020 Pazar

async ve await

Giriş
await, async ile beraber ya da tek başına kullanılabilir. Tek Başına await yazısına göz atabilirsiniz.

asycn Best Practices
Microsoft'un önerisi şöyle.
-change the signature of the async methods so that they return Task or Task<> (in TypeScript, that'd be a Promise<>)
-change the names of the async methods to end with xxxAsync()
async Return Type
async metodlar genelde Task, Task<T> veya void dönerler.

async Method ve ref Type
async metod içind ref type kullanılamaz.
Örnek
Elimizde şöyle bir kod olsun.
async Task MethodAsync(ref bool isCancelled)
{
  ...
}
Şöyle bir hata alırız.
CS1988: Async methods cannot have ref, in or out parameters
async ve await ikilisi
async ve await Continuation yapılacağı zaman kullanılır.  Yani şu async işaretli bir metod içinde bulunan şu kod parçası
var str = await SomeFuncAsync() //returning "test";
this.textBox1.Text = str;
aslında şuna eşittir.
Task.Factory.StartNew(() => { return "test"; } )
            .ContinueWith(task => { this.textBox1.Text = task.Result; },
                            CancellationToken.None,
                            TaskContinuationOptions.None, 
                            TaskScheduler.FromCurrentSynchronizationContext());
async ve StateMachine
async kelimesini gören derleyici
System.Runtime.CompilerServices.AsyncStateMachineAttribute
sınıfını kullanarak bir State Machine oluşturur.

async Event Handler
async Event Handler yazısına taşıdım.

async lambda
async Event Handler yazısına taşıdım.

deadlock
async metodlar eğer yanlış kullanılırsa deadlock'a sebep olabiliyor ancak .Net içindeki sınıflar async/await kullanmadıkları için rahatça kullanılabilir.

async metod içinde await ne işe yarar
await Task'ın bitmesini  beklemek için kullanılır. await ile Task.Factory. Start kullanılabilir.
public async Task FooAsync()
{
    int value = await Task.Factory.StartNew(
                        () => DoSomething(), TaskCreationOptions.LongRunning);
}
veya Task.Run'da kullanılabilir.
public async Task FooAsync()
{
    int value = await Task.Run(() => DoSomething());
}
veya asenkron çalışan bir metod çağrısı yapılır. Şöyle yaparız.
public static async Task <string> job()
{
  ...
  await Task.Delay(2000);
  ...
}
Eğer bunları yapmazsak şöyle bir hata alırız.
Severity Code Description Project File Line Column Warning CS1998 This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. 
Örneğin aşağdaki kod bu hatayı verir.
public async Task<int> GetData() {
        return 1;
}
await çağrıları Short Circuit Evaluation Yaparlar
Örnek
Elimizde şöyle bir kod olsun. Çıktı olarak sadece "Tested" alırız. Çünkü ilk await false döner.
async Task Main()
{
    if (await first_check() && await second_check())
    {
        Console.WriteLine("Here?");
    }
    Console.WriteLine("Tested");
}

Task<bool> first_check() => Task.FromResult(false);
Task<bool> second_check() {
  Console.WriteLine("second_check");
  return Task.FromResult(true);
}
async metod içinde await ve SyncronizationContext
await çağrılınca altta devam eden kodun kendisini çağıran thread içinde çalışması için SynchronizationContext'i saklar. Şöyle bir kodumuz olsun.
public async Task X()
{
    A();
    await BAsynch();
    C();
}
await çağrısından sonra gelen C() şu hale getirilir.
public Task X()
{
    A();
    return BAsynch().ContinueWith(()=>{ C(); })
}
Dolayısıyla artık Invoke(), BeginInvoke() gibi metodları kullanmaya gerek kalmıyor.

SyncronizationContext Her Thread'de Bulunur mu ?
SynchronizationContext GUI thread'lerinde bulunur ancak konsol thread'lerinde bulunmaz. Dolayısıyla konsolda çalışan bu örnekte farklı sonuçlar görebiliriz.
static  void Main(string[] args)
{
  Console.WriteLine("Main: " + Thread.CurrentThread.ManagedThreadId);//8
  MainAsync(args).Wait();
  Console.WriteLine("Main End: " + Thread.CurrentThread.ManagedThreadId);//8

  Console.ReadKey();
}


static async Task MainAsync(string[] args)
{
  Console.WriteLine("Main Async: " + Thread.CurrentThread.ManagedThreadId);//8

  await thisIsAsync();
}

private static async Task thisIsAsync()
{
  Console.WriteLine("AsyncStart: " + Thread.CurrentThread.ManagedThreadId);//8
  await Task.Delay(1);
  Console.WriteLine("AsyncEnd: " + Thread.CurrentThread.ManagedThreadId);//9

}
async metod içinde await ve Exception
Şöyle yaparız.
async void btncheckPassword_Click(object sender, EventArgs e)
{

  try
  {
    await Task.Run(
      () => 
      {  
        try
        {
          ... //Exception thrown from async method
        }
        catch
        {
          throw new XXX(); //Catch and throw XXX
        }
      }); 

  }
  catch (XXX e) //Code is executed in SynchronizationContext
  {
    ...
  }
}






Hiç yorum yok:

Yorum Gönder