110mat110
110mat110

Reputation: 624

Asynchronous tasks c#

I am trying to understand asynchronous programming in C#. I created an example of a function that can be called only once. For example reading from a big file. I want to create a query and request will wait in query until they can safely read file.

AsyncWork aw = new AsyncWork();

Task.Run(() => {
    for (int count = 0; count < 10; count++) {
        aw.DoAsyncWork(count);
        Console.WriteLine("request added");
    }
});
Console.ReadKey();

and AsyncWork

public class AsyncWork {
    int Requests = 0;
    int Workers = 0;

    public AsyncWork() { }

    public async Task DoAsyncWork(int count) {
        Requests++;

        while (Workers > 0) ;

        Workers++;
        Requests--;

        if (Workers > 1) Console.WriteLine("MORE WORKERS AT ONCE");

        Console.WriteLine(count.ToString() + " Started task");
        //reading from file
        await Task.Delay(1000);
        Console.WriteLine(count.ToString() + " Ended task");

        Workers--;
    }
}

I expected that I will have 10 requests and then they will be done one by one. But output is like:

0 Started task
request added
0 Ended task
1 Started task
request added
1 Ended task
2 Started task
request added
2 Ended task
3 Started task
request added
3 Ended task
4 Started task
request added
4 Ended task
5 Started task
request added
5 Ended task
6 Started task
request added
6 Ended task
7 Started task
request added
7 Ended task
8 Started task
request added
8 Ended task
9 Started task
request added
9 Ended task

Why it is running synchronously?

Upvotes: 3

Views: 165

Answers (1)

Servy
Servy

Reputation: 203820

When you run the code your first worker will start working, then the next will get stuck in the busy loop that you have, while (Workers > 0) ; and won't move on until the previous worker finishes. Then when it starts the next worker will be stuck there, and so on, for each iteration of the loop in which you start the workers.

So you only ever have at most one worker doing work, and one worker pegging an entire CPU sitting there waiting for it to finish.

A proper way to synchronize access when writing asynchronous code is to use a SemaphoreSlim and use WaitAsync, which will asynchronously wait until the semaphore can be acquired, rather than synchronously blocking the thread (and pegging the CPU while you're at it) for the other workers to finish. It also has the advantage of being safe to access from multiple threads, unlike an integer which is not safe to change from multiple threads.

Upvotes: 4

Related Questions