Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to simulate an expensive operation with async?

Is the code from this page really the best way to simulate a long running task?

The console app I've worked up is fairly simple and seems to work just fine.

I'm not sure if I could swap out DoExpensiveCalculation for an an Async method, like GetStringAsync from HttpClient without issue.

using System;
using System.Threading.Tasks;

namespace ExpensiveAsync
{
    public class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("started");

            var t = CalculateResult("stuff and that");

            Console.WriteLine("press return");
            Console.ReadLine();
        }

        public static async Task<string> CalculateResult(string data)
        {
            // This queues up the work on the threadpool.
            var expensiveResultTask = Task.Run(() => DoExpensiveCalculation(data));

            // Note that at this point, you can do some other work concurrently,
            // as CalculateResult() is still executing!

            Console.WriteLine("concurrent");

            // Execution of CalculateResult is yielded here!
            var result = await expensiveResultTask; // CalculateResult returns the Task object here

            Console.WriteLine("synchronous"); // this code runs once the DoExpensiveCalculation method has finished

            return result;
        }

        public static string DoExpensiveCalculation(string data)
        {
            var completionTime = DateTime.Now.AddSeconds(3);

            Console.WriteLine("begin");

            while (DateTime.Now < completionTime) ;

            Console.WriteLine("finish");

            return data;
        }
    }
}
like image 891
Matt W Avatar asked Oct 28 '25 08:10

Matt W


1 Answers

The structure of the code implies that DoExpensiveCalculation is a CPU-bound operation. If you want to stub out a CPU-bound operation without taking up CPU, Thread.Sleep is the appropriate option.

I'm not sure if I could swap out DoExpensiveCalculation for an an Async method, like GetStringAsync from HttpClient without issue.

Well, that's completely different. GetStringAsync is not a CPU-bound operation; it's an I/O-bound operation.

I/O-bound operations are naturally asynchronous, and they can be used directly with async and await. CPU-bound operations are naturally synchronous, so that's where you sometimes want to use Task.Run. "Sometimes" in this case generally means "when you're on a UI thread", so that the UI isn't frozen while the CPU-bound operation is running. When you wrap the CPU-bound operation in a Task.Run, you can then treat it as asynchronous, i.e., awaiting it from the UI thread.

Your example code is a console app, where the use of Task.Run is usually not necessary. Console apps generally run whatever code they need to run and exit; in most cases there's no UI that needs to be kept responsive, and thus no need for Task.Run.

like image 52
Stephen Cleary Avatar answered Oct 30 '25 23:10

Stephen Cleary



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!