26 Kasım 2020 Perşembe

Task.WhenAll metodu

Giriş
WaitAll metodundan farklı olarak tüm Task'ların sonuçların alabilmemizi sağlar. await ile kullanılmak üzere tasarlanmıştır.

Örnek
Tüm sonuçları bir diziye almak için şöyle yaparız.
object[] allObjectAttributes = await Task.WhenAll(
    Task.Run(() => ...),
    Task.Run(() => ...),
    Task.Run(() => ...),
    Task.Run(() => ...)
);
Örnek
Şöyle yaparız.
public static async Task Run()
{
  List<Task> tasks = new List<Task>();

  Task t1 = Task.Run(()=>...);
  Task t2 = Task.Run(() =>...);

  tasks.Add(t1);
  tasks.Add(t2);

  await Task.WhenAll(tasks);  //ERROR IS THROWN HERE
  Console.WriteLine("All tasks completed");
}
Örnek
Linq ile tüm sonuçları dolaşmak için şöyle yaparız.
private static async Task<string> checkAvaibleAsync(string url)
{
  using (var client = new HttpClient())
  {
    string htmlCode = await client.GetStringAsync(url); 

    if (...)
      return url;
    else
      return null;
  }
}
Bu metodu şöyle çağırırız.
private static async Task<string[]> searchForLinksAsync()
{
  string url = "http://www.xxxx.pl/xxxx/?action=xxxx&id=";

  var tasks = Enumerable.Range(0, 2500).Select(i => checkAvailableAsync(url + i));
  var results = await Task.WhenAll(tasks);
  var listOfUrls = results.Where(x => x != null).ToArray();

  Console.WriteLine(listOfUrls.Length);
  Console.ReadLine();
}



Task Sınıfı Converging Back to The Calling Thread

Giriş
Açıklaması şöyle
On the same threads synchronization topic, the Task library enables several ways to wait until other tasks have finished their execution. This is a significant expansion of the usage of the Thread.Join concept.

The methods Wait , WaitAll , and WhenAny are different options to hold the calling thread until other threads have finished.
Wait metodu
Örnek ver

WaitAll metodu 
Task.WaitAll metodu yazısına taşıdım.

WhenAny metodu
Örnek ver

WhenAll metodu
Task.WhenAll metodu yazısına taşıdım.

Task Sınıfı Continuation

Giriş
Açıklaması şöyle
Before using the Task library, we had to use callback methods, but with TPL, it is much more comfortable. A simple way to chain threads and create a sequence of execution can be achieved by using Task.ContinueWith method. The ContinueWith method can be chained to the newly created Task or defined on a new Task object.

Another benefit of using the the the ContinueWith method is passing the previous task as a parameter, which enables fetching the result and processing it.
ContinueWith metodu - Action
Şöyle yaparız. ContinueWith metoduna geçilen parametre ana Task nesnesidir.
var t1 = new Task(() => ...);
var t2 = t1.ContinueWith((t) => ...);
t1.Start();
ContinueWith metodu - Action + TaskContinuationOptions
Açıklaması şöyle
The ContinueWith method accepts a parameter that facilitates the execution of the subsequent thread, TaskContinuationOptions, that some of its continuation options I find very useful:

- OnlyOnFaulted/NotOnFaulted (the continuing Task is executed if the previous thread has thrown an unhandled exception failed or not);
- OnlyOnCanceled/NotOnCanceled (the continuing Task is executed if the previous thread was canceled or not).

You can set more than one option by defining an OR bitwise operation on the TaskContinuationOptions items.
Örnek
Şöyle yaparız
// Initiate a library account object
LibraryAccount libraryAccount = new LibraryAccount(booksAllowance);
Task<int> task = Task.Factory.StartNew<int>(() =>{
  // The first task withdraws books
  libraryAccount.WithdrawBooks(booksToWithdraw);
  return libraryAccount.BorrowedBooksCount;
  })
  .ContinueWith<int>((prevTask) => {
    // Fetching the result from the previous task
    int booksInventory = prevTask.Result;
    Trace.WriteLine($"Current books inventory count {booksInventory}");
    // Return the books back to the library
    libraryAccount.ReturnBooks(booksToWithdraw);
    return libraryAccount.BorrowedBooksCount;
  }, // Set the conditions when to continue the subsequent task
  TaskContinuationOptions.NotOnFaulted | 
  TaskContinuationOptions.NotOnCanceled |
  TaskContinuationOptions.OnlyOnRanToCompletion);
  
// Wait for the task to end before continuing the main thread.
task.Wait();
// The actual number of books should remain the same
Assert.Equal(task.Result, booksAllowance);
ContinueWith metodu - Action + TaskScheduler
Örnek
Eğer task UI thread içinde başlatıldıysa arka plan iş bittikten sonra UI nesnesini güncellemek için şöyle yaparız.
public Action Worker = ...;
Task.Factory
    .StartNew(Worker)
    .ContinueWith(t => 
    { 
      ...
    }, TaskScheduler.FromCurrentSynchronizationContext()
);
Örnek
Şöyle yaparız

ContinueWhenAll metodu
Açıklaması şöyle
Besides calling the ContinueWith method, there are other options to run threads sequentially. The TaskFactory class contains other implementations to continue tasks, for example, ContinueWhenAll or ContinueWhenAny methods. The ContinueWhenAll method creates a continuation Task object that starts when a set of specified tasks has been completed. In contrast, the ContinueWhenAny method creates a new task that will begin upon completing any task in the set that was provided as a parameter.


29 Eylül 2020 Salı

C# 8 Ranges syntax

Örnek
Şöyle yaparız. İçinde 0 ve 1 olan iki elemanlı dizi yaratır
var slice = myArray[0..2];

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
  {
    ...
  }
}