David Klempfner
David Klempfner

Reputation: 9870

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>
*/

Upvotes: 3

Views: 896

Answers (3)

Thomas
Thomas

Reputation: 5240

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.

Upvotes: 6

Johnny
Johnny

Reputation: 9519

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);

Upvotes: 2

Jesse Johnson
Jesse Johnson

Reputation: 1718

You are likely creating a new thread in the GetIntAfterLongWait() method. Try changing return new Task<int>(() => 23); to return Task.FromResult(23);.

For more information on Task.FromResult see the MSDN Documentation (with a good example) on How to: Create Pre-Computed Tasks

Upvotes: 0

Related Questions