P3310_ELopy
P3310_ELopy

Reputation: 13

C# await of Task is endless

I'm trying to use following async extention method:

public static async Task<MyClass<T>> ToMyClass<T>(this Task<T> source)
{
    \\ some logic
    return new MyClass<T>(await source);
}

by writing this test method:

public async void Test()
{
    Task<int> task = new Task<int>(() => 10);
    var result = await task.ToMyClass();
    task.Start();
    Assert.True(result.Value == 10);
}

But all I've got is infinite waiting. I have tried remove await keyword, apply it to task like this (await task).ToMyClass(), but it leaded me only to infinite waiting or exceptions. When I changed usage of task to Task.Run method:

var result = await Task.Run(() => 10).ToMyClass();

everything worked well. What am I doing wrong while using constructor and Start() method? And what is the difference beetween these two ways?

Upvotes: 1

Views: 482

Answers (2)

TemaTre
TemaTre

Reputation: 1424

So, you try to wait before start.

 var result = await task.ToMyClass();
 task.Start();

You should start it before awaiting

Upvotes: 0

Saeb Amini
Saeb Amini

Reputation: 24459

There are a couple of differences here.

As @GSerg has mentioned in the comment, the Task constructors are a bit special because they create a "cold" task that doesn't run until you explicitly start it with the Start method. Relevant info from the docs:

Tasks that are created by the public Task constructors are referred to as cold tasks, because they begin their life cycle in the non-scheduled Created state and are scheduled only when Start is called on these instances.

With that explanation, it becomes obvious why you're waiting infinitely: because you're waiting on something that hasn't started yet, and so is never going to complete.

So if you swap the order of your task.Start(); and var result = await task.ToMyClass(); lines, starting the task before waiting on it, that should solve the infinite wait issue:

public async void Test()
{
    Task<int> task = new Task<int>(() => 10);
    task.Start();
    var result = await task.ToMyClass();
    Assert.True(result.Value == 10);
}

Note that while Task.Run gives you a "hot"(started) task, which doesn't have that problem, it also has a different effect, in that it schedules whatever you pass to it to a Thread Pool thread (not a good idea server-side like ASP.NET), whereas Tasks, in general, don't necessarily involve threads.

Upvotes: 2

Related Questions