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;
        }
    }
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With