Async functions question

BIT64

New member
Joined
Jan 1, 2023
Messages
1
Programming Experience
1-3
Hello,

I am new to async functions and I am wondering why my code is not working. I simply do a for loop where I do amount ++ up to 100 000 000. For my single thread I do a for loop twice.
Then for my async I create a list of task, execute the list and wait for the list to be done.
The problem is it seems to take twice as long for my code to execute in async.

code:
using System;
using System.Threading.Tasks;
using System.Diagnostics;       //stop watch functions
using System.Runtime.CompilerServices;
using System.Collections.Generic;

Console.WriteLine("How long for non-async vs async task");
Stopwatch sw = new Stopwatch();
//starting single thread task
Console.WriteLine("Starting the timer for single thread heavy task");
sw.Start();
for (var i = 0; i < 2;i++)
{
    bigTask();
}
sw.Stop();
Console.WriteLine("The bigTask took this long to execute 2 times " + sw.Elapsed.TotalSeconds);
sw.Reset();
//starting async thread task
Console.WriteLine("Starting the timer for async thread heavy task");
sw.Start();
//bigTaskAsync();
var task = new List<Task> {bigTaskAsync(),bigTaskAsync()};
await Task.WhenAll(task);
sw.Stop();
Console.WriteLine("The bigTask took this long to execute 2 times " + sw.Elapsed.TotalSeconds);
sw.Reset();
void bigTask()
{
    var amount = 0;
    for (var i = 0; i < 100_000_000; i++)
    {
        amount++;
    }
}
 async Task bigTaskAsync()  //to return a value from a task do <value type>   EX:   async Task<int> bigTaskAsync()
{
    var amount = 0;
    for (var i = 0; i < 100_000_000; i++)
    {
        amount++;
    }
}


Results of execution

How long for non-async vs async task
Starting the timer for single thread heavy task
The bigTask took this long to execute 2 times 0.2910466
Starting the timer for async thread heavy task
The bigTask took this long to execute 2 times 0.6385708
 
To async is not the cure all for performance problems. What it facilitates is the ability to do more when doing I/O bound operations. What you have there is a CPU bound operation. Also be aware that thread pools are not free, there is an associated cost to do the switching between threads.
 
On closer look at your code, also not that you are not actually doing any asynchronous work nor pushing work to the thread pool. On line 23 you are calling bigTaskAsync(). At no point inside bigTaskAsync() are you doing anything to yield control back, so everything is effectively done synchronously, one at a time.
 
For my single thread
Take care; TAP isn't necessarily multithreading in the way developers probably typically think about multithreading - it's about making more efficient use of fewer threads by not wasting a thread on waiting for some long operation to complete.

If it were an office, multithreading is about hiring one person to make coffees and another person to refill the laser printers and that is all they do; if the kettle is heating up, the coffee maker sits and waits for it. If the printer still has paper the refiller sits and waits for it to run out. It's very expensive to hire two people who spend more their time sitting around doing nothing.

TAP is about hiring one person who makes coffee until they have to wait for the kettle to boil then they look for another job; oh a printer has run out of paper - they refill it then look for another job to do. If the kettle isn't done yet, they do something else (like vacuuming the floor). Eventually they might sit down for a rest but in a busy office they will be doing hundreds of little jobs, progressing each one until they get blocked on it (can't vacuum the board room; it's in use) and go find something else - oh, kettle 1 has finished boiling, time to make coffee with it)

It's very cheap to hire 1 person that can do 100 jobs, but you might eventually need more of them if there is too much work for one person to complete - that's when to multithread, but that isn't necessarily your problem

C#:
using System;
using System.Threading.Tasks;
using System.Diagnostics;       //stop watch functions
using System.Threading;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

Console.WriteLine("How long for non-async vs async task");
Stopwatch sw = new Stopwatch();
Console.WriteLine("Starting the timer for single thread heavy task");
sw.Start();
bigTask("coffee");
bigTask("printer");
sw.Stop();
Console.WriteLine("The bigTask took this long to execute 2 times " + sw.Elapsed.TotalSeconds);
sw.Reset();

Console.WriteLine("Starting the timer for async thread heavy task not really");
sw.Start();
await Task.WhenAll(bigTaskAsyncNotReally("coffee"), bigTaskAsyncNotReally("printer"));
sw.Stop();
Console.WriteLine("The bigTask took this long to execute 2 times " + sw.Elapsed.TotalSeconds);
sw.Reset();

//starting async thread task
Console.WriteLine("Starting the timer for async thread heavy task");
sw.Start();
await Task.WhenAll(bigTaskAsync("coffee"),bigTaskAsync("printer"));
sw.Stop();
Console.WriteLine("The bigTask took this long to execute 2 times " + sw.Elapsed.TotalSeconds+  " and thread id " + Thread.CurrentThread.ManagedThreadId);
sw.Reset();

void bigTask(string what)
{
    for (var i = 0; i < 10; i++)
    {
        Console.WriteLine("btsync" + i + " doing " + what +" on thread id " + Thread.CurrentThread.ManagedThreadId);
        Thread.Sleep(1);
    }
}
async Task bigTaskAsyncNotReally(string what)  //to return a value from a task do <value type>   EX:   async Task<int> bigTaskAsync()
{
    for (var i = 0; i < 10; i++)
    {
        Console.WriteLine("btasyncnot" + i + " doing " + what +" on thread id " + Thread.CurrentThread.ManagedThreadId);
        Thread.Sleep(1);
    }
}
 async Task bigTaskAsync(string what)  //to return a value from a task do <value type>   EX:   async Task<int> bigTaskAsync()
{
    for (var i = 0; i < 10; i++)
    {
        Console.WriteLine("btasync" + i +  " doing " + what +" on thread id " + Thread.CurrentThread.ManagedThreadId);
        await Task.Delay(1); //control goes back to caller
    }
}

Look how the sync one prints 0 to 10 on the same thread, the NotReallyAsync one does the same, and the Async one mixes the 0 to 10 up

Always pay heed to this warning - it's telling you that this will occur:


1672644505031.png



In your code, an `await` is the point at which the kettle has been switched on and you have to wait for it, so it goes off to do something else. No await, no "going to find another job to do"
 
Last edited:
Back
Top Bottom