Await new Task<T>( ... ) : Task does not run?
Solution 1
To create a Task already started
Try creating the task like this:
Task.Factory.StartNew<object>((Func<Task<object>>) ...);
To create a Task without starting it
If you don't want the task started, just use new Task<object>(...)
as you were using, but then you need to call Start()
method on that task before awaiting it!
My recommendation
Just make a method that returns the anonymous function, like this:
private static Func<object> GetFunction( ) {
return (Func<object>)(( ) => {
SimpleMessage.Show( "TEST" );
return new object( );
} );
}
Then get it and run it in a new Task
whenever you need it (Also notice that I removed the async/await
from the lambda expression, since you are putting it into a Task already):
Task.Factory.StartNew<object>(GetFunction());
One advantage to this is that you can also call it without putting it into a Task
:
GetFunction()();
Solution 2
You should never use the Task
constructor (or Task.Start
).
I do not want this function to return a task that is already running ( that is IMPERATIVE ).
So, you want to return some code that won't execute until you call it? That's a delegate, not a Task
.
private static Func<Task<object>> GetInstance()
{
return async () =>
{
await SimpleMessage.ShowAsync("TEST");
return new object();
};
}
When you're ready to execute it, call it just like any other delegate. Note that it returns a Task
, so you can await
the result:
var func = GetInstance();
// Delegate has not started executing yet
var task = func();
// Delegate has started executing
var result = await task;
// Delegate is done
Solution 3
You are stuck with a bad design there. I'll try to make something work for you under these constraints.
The only way to delay start tasks is to use the Task.Start
method. (You also can use RunSynchronously
but that doesn't really make use of any of the tasks features. At this point the task becomes an unthreaded lazy object.
So use the Task.Start
method.
await
does not start tasks. It waits for tasks that already run. Therefore await new Task(() => { })
always freezes forever.
Another problem here:
return new Task<object>( (Func<Task<object>>)(async ( ) => {
await SimpleMessage.ShowAsync( "TEST" );
return new object( );
} ) );
When you start that task it will complete nearly instantly and Task.Result
will hold another task - the one returned by the async lambda. I doubt this is what you want. Hard to make this work and I don't know what you need.
This smells like the XY problem. Can you elaborate on what you want to accomplish? It feels like you have given yourself unnecessary constraints.
Will
Updated on June 05, 2022Comments
-
Will almost 2 years
A continuation of a question asked here :
In the aforementioned question I have the following function which returns an object of type Task (for incremental testing purposes) :
private static Task<object> GetInstance( ) { return new Task<object>( (Func<Task<object>>)(async ( ) => { await SimpleMessage.ShowAsync( "TEST" ); return new object( ); } ) ); }
When I call
await GetInstance( );
, the function is called (and I assume the task is returned since no exception is thrown) but then the task just sits there.I can only guess I am doing this wrong then.
I do not want this function to return a task that is already running ( that is IMPERATIVE ).
How do I asynchronously run the task returned by this function?
-
Will over 8 yearsWait - Won't that START the task? I need to return the task without it starting, and then start it again. I thought I was pretty specific about that (If it doesn't start the task then it's fine but this looks like it returns a task that's already running to me...)
-
Will over 8 yearsI think it would be better taken into chat - No need to transcribe war and peace here... now I just need to figure out how to start a chat session without being prompted to do so...
-
Lukazoid over 8 yearsWhy would you use
dynamic
when you know the type? -
Will over 8 yearsThank you - but there is more to this than what you think. I need the task because I need it to support task cancellation and restarting. I did not want to bog down the question with what I felt to be details not pertinent to the immediate question.
-
Stephen Cleary over 8 years@Will: This can work fine with cancellation. What exactly do you mean by "restarting"?
-
Incerteza over 8 yearsWhy should one never use Task constructor or Start?
-
Stephen Cleary over 8 years@アレックス: I explain in full on my blog (constructor and
Start
). -
Will over 8 years@StephenCleary : I mean that there is a long-running task in play which executes functions in the background. The task should be one that can be cancelled and started again with relative impunity. Using a Task seemed like the natural choice (given the presence of the CancellationTokenSource class (or whatever it's called I'm too tired to look it up...).
-
Will over 8 yearsSaw your edit : I like that. It looks good... Once I get out of the spiders web I'll have to try it...
-
Stephen Cleary over 8 years@Will:
CancellationToken
works fine with any kind of code. Restarting tasks is not possible; tasks have to be recreated. If you take theFunc<Task>
approach, you can create a replacement task by just calling the delegate again. -
Will over 8 years@StephenCleary : I know that. The problem into which I was running (again; a whole lot of stuff going on beyond what I posted) was that if the user acted... well, like a USER, you would end up with multiple tasks running right next to each other. Train wreck. When I say "Restart" I mean exactly what you say - get a new task and run it... My solution to the "Train Wreck" is to obtain the task and monitor it. I have to monitor the status when the button responsible for launching (and cancelling) it is pressed because cancelling the task isn't instantaneous. The task runs until it hits CT.Throw
-
Will over 8 years@StephenCleary (Continued) : and as users can just hammer away at the button you could end up with (like I said) a train wreck in which multiple tasks are running towards cancellation at the same time. Rather than just let the user mash the button it has to watch the status of the task. Is it just created? Good : run it. No? Has cancel been called on the cancellation token? No? Fine : Cancel it. Has that happened? Okay : Scream at the user to stop being stupid; once the task has been cancelled (correctly) then the CTS will be disposed of and restored so that the process can start again.
-
Will over 8 yearsDING There's been a development... chat.stackoverflow.com/rooms/97243/await-new-taskt
-
Will over 8 yearsPlease see stackoverflow.com/questions/34147144/…
-
Stephen Cleary over 8 years@Will: Just use a
Lazy<Task>
then, with aCTS.IsCancellationRequested
check. -
Will over 8 yearsI've already gotten where I need to be (unless what you are suggesting would resolve my new problem here : stackoverflow.com/questions/34147144/… ); Thanks.
-
The Sharp Ninja over 8 yearsFor some reason the compiler would not recognize the nested Task<object>. Using dynamic allowed it to skip the compiler and at run time get to the second task result.
-
Lukazoid over 8 yearsThat's because
FooGet()
is creating and returning aTask<object>
and notTask<Task<object>>
(which is what it actually is). -
Joanvo over 8 yearsOf course, I assumed that was what you wanted because you were awaiting it. Otherwise you should call Task.Start()?
-
Joanvo over 8 yearsI modified my answer, hope it helps
-
Will over 8 yearsGiven the complexity of the situation with which I am dealing this question is out of the scope of consideration (TL;DR : I was doing it wrong). However your answer is the correct approach for creating a task and returning it without starting it.