-1

According to Microsoft Article here, It's better to use Threading for CPU-Bound tasks and Async\Await for IO-Bound. On the other hands, some post like here says: If you're talking about consuming asynchronous operations, async/await works excellently for both I/O-bound and CPU-bound. I know that Async\Await just uses the current context(single current Thread) and when an encounter with the time-consuming command, it returns control to man caller until the answer arrives.

With the above information, I have tried to test Sync\Await in a DotNet Windows application with the following code:

class SampleClass
{
    public  async Task<double> TestAsync()
    {
         HttpClient client = new HttpClient();

        Task<double> doIt =  DoWork();

        double result = await doIt;

        return result;  
    }

     private async Task<double> DoWork()
    {
        //Line24: It takes a 4-sec CPU-Bound task and locks GUI when running
        TimeConsumingCPUBound();

        //Line27: It takes a 10-sec IO-Bound task and doesn't lock GUI when running
        await Task.Delay(10000);

        return 0;
    }

    public void TimeConsumingCPUBound()
    {
        string x = "";
        for (int i = 0; i < 50000; i++)
        {
            x = x + i.ToString();
        }
    }
}

and here I call The code inside a bottom handler:

 private async void button1_Click(object sender, EventArgs e)
    {
        SampleClass d = new SampleClass();
        await d.TestAsync();

    }

My question is Why is in line24(CPU-Bound) GUI is locked But in line27(IO-Bound) isn't it? I expected that in both of them GUI would be free!

Mohammad
  • 1,197
  • 2
  • 13
  • 30
  • *"I know that Async\Await just uses the current context (single current Thread) and when an encounter with the time-consuming command, it returns control to main caller until the answer arrives."* <== What you know is wrong IMHO. Whether the command is time-consuming or not is irrelevant. What is relevant is whether the command is an awaited incomplete asynchronous operation or not. – Theodor Zoulias Feb 22 '21 at 20:24
  • @TheodorZoulias I told this according this article (https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2012/hh191443(v=vs.110)?redirectedfrom=MSDN#threads) which says The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread – Mohammad Feb 22 '21 at 21:32
  • Mohammad this quote from the docs is correct, but how does it validate your statement about *"the time-consuming command"*? "Time-consuming" does not imply "asynchronous" IMHO. A synchronous, blocking, operation can be time-consuming too. – Theodor Zoulias Feb 23 '21 at 05:01
  • @TheodorZoulias Yes I agree with you, By the way, what did you mean by "awaited incomplete asynchronous operation"? – Mohammad Feb 23 '21 at 14:39
  • 1
    I mean `Task`s or other awaitables (like `ValueTask`s for example), that have their `IsCompleted` property equals to `false` at the time you `await` them. This is what causes the async state machine to box the continuation and return the control to the caller. Otherwise (if the task is completed) the method does not return, and instead continues running until the next `await`, or until the end of the method. – Theodor Zoulias Feb 23 '21 at 14:53
  • 1
    @TheodorZoulias Thanks friend for your great clarification. – Mohammad Feb 23 '21 at 15:01

1 Answers1

3

Asynchronous methods begin executing synchronously.

As noted in the article you linked, "You can use Task.Run to move CPU-bound work to a background thread":

private async Task<double> DoWork()
{
  await Task.Run(() => TimeConsumingCPUBound());

  await Task.Delay(10000);

  return 0;
}
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Thanks, But why my question seems bad? – Mohammad Feb 22 '21 at 19:19
  • Thanks, Task. Run make a new thread? isn't it? can I conclude Async (without Task? Run, Just work in IO-bound that have a IO-delay? I am going to read your nice article – Mohammad Feb 22 '21 at 19:21
  • @Mohammad: `Task.Run` queues work to the thread pool, so its delegate will be run on a thread pool thread. – Stephen Cleary Feb 22 '21 at 19:23
  • Yeah, I meant it uses a new threat rather than the current context thread. – Mohammad Feb 22 '21 at 19:25
  • My problem is about async/await capability. Is it correct to say it just works fine for IO-Bound to return control to the caller? On the other hand, it cannot return the controller in the CPU-Bound process!? – Mohammad Feb 22 '21 at 19:28
  • 2
    @Mohammad: `await` will return to the caller if its task isn't complete. In your example, `DoWork` does the CPU-bound work *before* returning the task. – Stephen Cleary Feb 22 '21 at 19:31