Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Declaring method return type Task<int> without async keyword

In what situation would you return a Task<T> without using async in the method signature?

I've got such a method in the below code but am having trouble understanding what's going on.

Why does my example code below not execute past any of the await statements? ie. why do Console.WriteLine("4)"); and Console.WriteLine("3)"); and return x; never get executed?

class Program
    {
        static void Main(string[] args)
        {
            TestAsync testAsync = new TestAsync();
            testAsync.Run();

            Console.Read();
        }
    }

    public class TestAsync
    {
        public async void Run()
        {
            Task<int> resultTask = GetInt();
            Console.WriteLine("2)");
            int x = await resultTask;
            Console.WriteLine("4)");
        }
        public async Task<int> GetInt()
        {
            Task<int> GetIntAfterLongWaitTask = GetIntAfterLongWait();
            Console.WriteLine("1)");
            int x = await GetIntAfterLongWaitTask;
            Console.WriteLine("3)");
            return x;
        }

        public Task<int> GetIntAfterLongWait()
        {            
            Task.Run(() =>
            {
                for (int i = 0; i < 500000000; i++)
                {
                    if (i % 10000000 == 0)
                    {
                        Console.WriteLine(i);
                    }
                }
            });

            Console.WriteLine("Returning 23");
            return new Task<int>(() => 23);
        }
    }

/*
Output is:
Returning 23
1)
2)
<list of ints>
*/
like image 582
David Klempfner Avatar asked Sep 09 '26 10:09

David Klempfner


2 Answers

When you return a Task from a non-async method?

Task<T> is generalized spoken a promise for a future value. Whether you produce this promise from an async keyworded method or from another source (like a started thread or IO callbacks) is not of interest for the caller and only an implementation strategy. That is also the reason, why interfaces (or abstract method definition) do not have the async keyword at all (async/await is an implementation strategy).

Your code sample

  • Issue 1: Your method GetIntAfterLongWait is flawed in two ways. The first instantiated Task is instantiated and off-loaded to a thread, but the result is never picked up (so never awaited ... and never delaying anything).
  • Issue 2: The second task (the one you return in GetIntAfterLongWait) is created (by the constructor with a method to execute) but not started (Task.Start()). Other more simplier methods are the static Task.Run or (in this case) Task.FromResult. The task (or promise) never delivers the result, because the function block in the constructor is never executed.
  • Issue 3: The Main method does not await the result of the returned task (either by await or Task.Wait() or Task.Result.
like image 103
Thomas Avatar answered Sep 10 '26 23:09

Thomas


The problem in your code is that you are actually await never started task since the method GetIntAfterLongWait returns new instance of the task which is not started. So basically you have a deadlock, waiting for something which is not started at all.

You could return Task.FromResult(23) which is basically already completed task, or you could actually run your task Task.Run<int>(() => 23);

like image 35
Johnny Avatar answered Sep 10 '26 22:09

Johnny



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!