Gerard
Gerard

Reputation: 13397

Different behaviour of Task vs. Task<TResult>

In a console application I use async-await as follows:

static void Main(string[] args)
{
    // Task<Model>
    var taskGetModel = Testcases.GetModel(22);
    taskGetModel.Wait();

    // Task without TResult
    var taskSaveModel = Testcases.SaveModel(taskGetModel.Result);
    taskSaveModel.Wait();
}

public async static Task<Model> GetModel(int number)
{
    var baseData = await serviceagent.GetBaseData();

    var model = await serviceagent.GetModel(baseData, number);

    model.BaseData = baseData;

    return model;
}

public static async Task SaveModel(Model model)
{
    await serviceagent.SaveModel(model);
}

// as for the service methods:
public async Task SaveModel(Model model)
{
    // the method `.ToCommunication` has the signature:
    // public async Task<CommunicationModel> ToCommunication
    var commodel = await new Mapper().ToCommunication(model);
    // Proxy is the interface to the servce (ChannelFactory etc.)
    // the method `.Save` has the signature:
    // public async Task Save(CommunicationModel model)
    await Proxy.Save(commodel);
}
public async Task<Model> GetModel(BaseData baseData, int number)
{
   // NOT a task: CommunicationModel GetCommunicationModel
   var commodel = Proxy.GetCommunicationModel(baseData, number);
   // signature with Task: public async Task<Model> ToModel
   return await new Mapper().ToModel(baseData, commodel);
} 

In static main, the Task<TResult> gives the nice result that the function GetModel returns immediately with the Task and I can wait for its result to finish.

Why does the Task in SaveModel not return immediately?
The await in SaveModel is already awaited in that method. Is it because it doesn not have a TResult?

Upvotes: 3

Views: 1127

Answers (1)

Tim S.
Tim S.

Reputation: 56536

Works for me. The following code...

using System;
using System.Diagnostics;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            // Task<Model>
            var sw = Stopwatch.StartNew();
            Console.WriteLine("1: " + sw.Elapsed);
            var taskGetModel = GetModel(22);
            Console.WriteLine("2: " + sw.Elapsed);
            taskGetModel.Wait();
            Console.WriteLine("3: " + sw.Elapsed);

            // Task without TResult
            var taskSaveModel = SaveModel(taskGetModel.Result);
            Console.WriteLine("4: " + sw.Elapsed);
            taskSaveModel.Wait();
            Console.WriteLine("5: " + sw.Elapsed);
        }

        public async static Task<Model> GetModel(int number)
        {
            var baseData = await service.GetBaseData();

            var model = await service.GetModel(baseData, number);

            model.BaseData = baseData;

            return model;
        }

        public static async Task SaveModel(Model model)
        {
            await service.SaveModel(model);
        }

        static Service service = new Service();
        class Service
        {
            public Task SaveModel(Model model)
            {
                return Task.Delay(1000);
            }

            public async Task<Model> GetModel(object baseData, int number)
            {
                await Task.Delay(1000);
                return new Model();
            }

            public async Task<object> GetBaseData()
            {
                await Task.Delay(1000);
                return new object();
            }
        }
    }
    public class Model
    {
        public object BaseData { get; set; }
    }
}

Outputs something like

1: 00:00:00.0000102
2: 00:00:00.0087409
3: 00:00:02.0321182
4: 00:00:02.0356848
5: 00:00:03.0459510

Which is exactly what you'd expect. Maybe your service.SaveModel method is not implemented in a truly asynchronous fashion, and does a long-running operation before surrendering control? Here's an example of a bad implementation:

public Task SaveModel(Model model)
{
    Thread.Sleep(1000);
    return Task.Delay(0);
}

This makes it output:

1: 00:00:00.0000303
2: 00:00:00.0090621
3: 00:00:02.0345882
4: 00:00:03.0362871
5: 00:00:03.0365073

Upvotes: 2

Related Questions