Await new Task<T>( ... ) : Task does not run? - c#

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?

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!
[Reference]
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()();

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

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.

OK, I think I've figured this out. Please examine this code:
class Program
{
public static void Main(string[] args)
{
// Only RUN the task as needed. FooGet
// still allows you to generalize your task.
Task.Run(() =>
{
dynamic value = FooGet();
value.RunSynchronously();
Console.WriteLine(value.Result.Result.ToString());
});
while (true) Thread.Sleep(100);
}
private static Task<object> FooGet()
{
var task = new Task<object>(() => {
return asyncBar();
});
return task;
}
private async static Task<object> asyncBar()
{
// do work!
return "Hello, world!";
}
}

Related

Func doesn't work & blocked during test execution

Prerequisites:
.Net 6.0
C# 10
NUnit 3.13.3
Context:
Try to run an unit test, but run into some kind of thread blocker. The code just stop execution on
value = await getDataToCacheAsync.Invoke();
The last row that can be debugged is
return () => new Task<string?>(() => cacheValue [there]);
Q: It looks like there is some kind of deadlock happened, but it's not clear for me why and how it can be addressed
Unit test:
[Test]
public async Task GetCachedValueAsync_WithDedicatedCacheKey_ReturnsExpectedCacheValue()
{
const string cacheKey = "test-cache-key";
const string cacheValue = "test-cache-key";
var result = await _sut.GetCachedValueAsync(cacheKey, GetDataToCacheAsync(cacheValue));
Assert.AreEqual(cacheValue, result);
}
private static Func<Task<string?>> GetDataToCacheAsync(string cacheValue)
{
return () => new Task<string?>(() => cacheValue);
}
The code under test:
public async Task<T?> GetCachedValueAsync<T>(string cacheKey, Func<Task<T?>> getDataToCacheAsync)
where T : class
{
// [Bloked here, nothing happens then, I'm expecting that it should return "test-cache-value"]
value = await getDataToCacheAsync.Invoke(); [Blocked]
...
return value
}
After
return () => new Task<string?>(() => cacheValue [there]);
was replaces with
return () => Task.FromResult(cacheValue);
it started work
UPD:
It seems like the root cause is that a task should be started directly before awaiting it, in such cases (e.g. Task.Run(...), TaskFactory ... etc.).
Task.FromResult returns already completed task with a result
As written in the docs generally you should try to avoid creating tasks via constructor:
This constructor should only be used in advanced scenarios where it is required that the creation and starting of the task is separated.
Rather than calling this constructor, the most common way to instantiate a Task object and launch a task is by calling the static Task.Run(Action) or TaskFactory.StartNew(Action) method.
The issue being that task created by constructor is a "cold" one (and according to guidelines you should avoid returning "cold" tasks from methods, only "hot" ones) - it is not started so await will result in endless wait (actually no deadlock happening here).
There are multiple ways to fix this code, for example:
Use Task.Run:
return () => Task.Run(() => cacheValue);
Start created task manually (though in this case there is no reason to. Also as noted by #Theodor Zoulias - it is recommended to specify explicitly the scheduler when calling the Start method. Otherwise the task will be scheduled on the ambient TaskScheduler.Current, which can be a source of some issues):
return () =>
{
var task = new Task<string?>(() => cacheValue);
task.Start();
return task;
}
Return a completed task (which I think is the best way in this case, unless you are testing a very specific scenario):
return () => Task.FromResult(cacheValue);

Async method that returns result and Task

I'm trying to design a public method that returns a quick result and, if needed, kicks off a long-running background task.
The result is retrieved within the method pretty quickly, and once it is retrieved it needs to be immediately available to the caller, without waiting for the potential background task to complete.
The background task is either not needed at all, or it must run for a significant amount of time - longer than the caller and all other logic in the program would take to complete without it.
Looking through the MS docs, the best design option I can come up with is to return two things from this method: the result, as well as a Task for the background task.
I don't see a better way to do this, but there are some downsides: first, the responsibility for making sure the background task completes falls on the caller of the method, even though the caller really just wants to consume the immediate result and not be concerned with the behind-the-scene stuff. Second, it is awkward to return null if the background task isn't needed to begin with: now the caller must ensure the task isn't null, in addition to making sure it completes if it is null.
What other options are available for this sort of situation?
Here's an example of what my current design looks like:
public async Task<Tuple<string, Task>> GetAndSave() {
var networkResult = await GetFromNetworkAsync();
if (NeedsToSave(networkResult)) {
var saveTask = SaveToDiskAsync(networkResult);
return new Tuple<string, Task>(networkResult, saveTask);
}
else {
return new Tuple<string, Task>(networkResult, null);
}
}
first, the responsibility for making sure the background task completes falls on the caller of the method, even though the caller really just wants to consume the immediate result and not be concerned with the behind-the-scene stuff.
If it's important to make sure the background task completes then instead of returning the Task you could hand it off to another object (that has been injected into the class that has your GetAndSave method). For example:
public class Foo
{
readonly Action<Task> _ensureCompletion;
public Foo(Action<Task> ensureCompletion)
{
_ensureCompletion = ensureCompletion;
}
public async Task<string> GetAndSaveAsync() // Your method
{
string networkResult = await GetFromNetworkAsync();
if (NeedsToSave(networkResult))
{
Task saveTask = SaveToDiskAsync(networkResult);
_ensureCompletion(saveTask); // This is a synchronous call... no await keyword here. And it returns `void`
}
return networkResult;
}
Task<string> GetFromNetworkAsync() {...}
bool NeedsToSave(string x) {...}
Task SaveToDiskAsync(string x) {...}
}
Now you can inject whatever follow-up behavior you desire for the saveTask. For example, you could write stuff out to the console depending on how it goes:
async Task DoStuff()
{
var foo = new Foo(async task =>
// ^^^^^ More on this in a moment
{
try
{
await task;
Console.Writeline("It worked!");
}
catch (Exception e)
{
Console.Writeline(e.ToString());
}
});
var immediateResult = await foo.GetAndSaveAsync();
// do stuff with `immediateResult`
}
Now, the thing that might be confusing about this (and the power behind this type of solution) is how you can have a synchronous call on the one hand:
_ensureCompletion(saveTask); // This is a synchronous call... no await keyword here
...that does asynchronous things:
var foo = new Foo(async task => ...);
// ^^^^^ This statement lambda is asynchronous
(The injected delegate might even write out to the console on a different thread than whatever thread called GetAndSaveAsync()!)
There's no magic here. It all comes down to SynchronizationContext and the inner workings of async/await.
When the compiler encounters the await keyword (in an async context) then it will do a few things:
Turn everything after the await into a continuation (basically a delegate with some state)
Replace the await keyword with something like SynchronizationContext.Current.Post(continuation)
In other words, this:
async void EnsureCompletion(Task task)
{
try
{
await task;
Console.Writeline("It worked!");
}
catch (Exception e)
{
Console.Writeline(e.ToString());
}
}
...gets turned into something like this:
void EnsureCompletion(Task task)
{
try
{
task.ContinueWith(t => SynchronizationContext.Current.Post(_ =>
{
if (t.IsCompletedSuccessfully)
{
Console.Writeline("It worked!");
}
else
{
Console.Writeline(task.Exception.ToString());
}
});
}
catch (Exception e)
{
Console.Writeline(e.ToString());
}
}
As you can see, EnsureCompletion is an entirely synchronous function that does (almost) the exact same thing as its asynchronous form. Notice how it returns void and everything. This is how you can jam an asynchronous statement lambda into a delegate parameter that has a synchronous signature.
I hinted that the console writing might happen on a totally different thread. That's because async/await is orthogonal to threading. It depends on whatever the currently assigned implementation of SynchronizationContext is programmed to do. Unless you're using WPF or WinForms then by default there will be no SynchronizationContext and continuations (the things that get passed to SynchronizationContext.Post) will just be tossed over to whatever thread happens to be free in the default thread pool.
Second, it is awkward to return null if the background task isn't needed to begin with: now the caller must ensure the task isn't null, in addition to making sure it completes if it is null.
I'm of the opinion that null was a design mistake in C#. (Ask me what some other ones are :) ). If you return null from this method:
public Task DoSomethingAsync()
{
return null; // Compiles just fine
}
...then anyone who uses it will encounter a NullReferenceException when they await it.
async Task Blah()
{
await DoSomethingAsync(); // Wham! NullReferenceException :(
}
(the reason why comes back to how the compiler desugurs the await keyword)
...and it's awkward to have to check for nulls everywhere.
Much better would be to just return Task.CompletedTask as #juharr said.
But if you just hand off the background task like I showed above then you don't have to worry about this.

Why await an async function directly not work without assigning it to a Task variable

Typically, I do the following
public static async Task dosth()
{
List<Task> job = new List<Task>();
for (int i = 0; i < 3; i++)
{
job.Add(sleep());
}
Task.WhenAll(job.ToArray());
}
static async Task sleep()
{
await Task.Delay(1000);
Console.WriteLine("Finish new");
}
It works smoothly, no problem. But when I do a review on my own code (trying using other syntax to do the same job), I suddenly figure out the following two are different.
public static async Task dosthA()
{
//This will be working synchronously, take 3 seconds.
await sleep();
await sleep();
await sleep();
//This will be working asynchronously, take 1 second only.
Task A = sleep();
Task B = sleep();
Task C = sleep();
await A;
await B;
await C;
}
Why assigning the async function to a new variable make difference? I originally think they are the same.
Update
Why it is confusing me is, actually in Microsoft doc on Async-await,
They stated the following in their code.
// Calls to TaskOfTResult_MethodAsync
Task<int> returnedTaskTResult = TaskOfTResult_MethodAsync();
int intResult = await returnedTaskTResult;
// or, in a single statement
int intResult = await TaskOfTResult_MethodAsync();
They are actually different, why they use //or , in a single statement, just because it makes no different in their own example?
This is because when you are returning a running Task when you call Sleep() even when you're assigning to a variable.
The confusion is that the Task does not begin if you assign it to a variable (A, B, or C) until you call await A; but that's not true. As soon as you assign sleep(); to A, sleep() was called; therefore the Task in the sleep() method is running. Assigning it to a variable or not the Task begins when you call the method; because in the method you start the Task.
Knowing this; when you call:
await A;
await B;
await C;
A, B, and C, have already starting simultaneously... After awaiting A it is most likely B, and C have also completed or are milliseconds from completing.
There are situations where you can reference a Task that hasn't started yet but you would have to purposely return a non-running Task to do that.
To answer the edit to your question also.
Tasks have a method called GetAwaiter() which returns a TaskAwaiter. In C# when you write var task = sleep(); then you're assigning the actual Task to the task variable. All the same when you write await sleep(); the compiler does some cool stuff and it actually calls the Task.GetAwaiter() method; which is subscribed to. The Task will run and when it is complete the TaskAwaiter fires the continuation action. This can't be explained in a simple answer but to know the outer logic helps.
Among other things the TaskAwaiter implements ICriticalNotifyCompletion which in turn implements INotifyCompletion. Both have one method each, OnCompleted(Action) and UnsafeOnCompleted(Action) (you can guess which is which by naming convention).
Another thing to note is that Task.GetAwaiter() returns a TaskAwaiter but Task<TResult>.GetAwaiter() returns a TaskAwaiter<TResult>. There's not a strong difference in the two but there is a difference in the GetResult() method of the two tasks; which is what's called while marshalling back to the proper threading context. The TaskAwaiter.GetResult() returns void and the TaskAwaiter<TResult>.GetResult() returns TResult.
I feel like if I push further into this I'll have to write pages to explain it all in detail... Hopefully just explaining your question and pulling the curtain back a little bit will shed enough light to help you both understand and dig deeper if you're more curious.
Ok, so based on the comment below I want to describe my answer a little bit further.
I'll start this simple; let's just make a Task; one that isn't running, and look at it first.
public Task GetTask()
{
var task = new Task(() => { /*some work to be done*/ });
//Now we have a reference to a non-running task.
return task;
}
We can now call code like:
public async void DoWork()
{
await GetTask();
}
… but we'll be waiting forever; until the application ends, because the Task was never started. However; we could do something like this:
public async void DoWork()
{
var task = GetTask();
task.Start();
await task;
}
… and it will await the running Task and continue once the Task is complete.
Knowing this you can make as many calls to GetTask() as you like and you'll only be referencing Tasks that have not started.
In your code it's just the opposite, which is fine, as this is the most used way. I encourage you to make sure your method names notify the user of how you're returning the Task. If the Task is already running the most common convention is the end the method name with Async. Here's another example doing it with a running Task for clarity.
public Task DoTaskAsync()
{
var task = Task.Run(() => { /*some work to be done*/ });
//Now we have a reference to a task that's already running.
return task;
}
And now we will most likely call this method like:
public async void DoWork()
{
await DoTaskAsync();
}
However; note that if we simply want to reference the Task just like we did earlier, we can, the only difference is this Task is running where the one prior was not. So this code is valid.
public async void DoWork()
{
var task = DoTaskAsync();
await task;
}
The big take away is how C# handles the async / await keywords. async tells the compiler that the method is going to become a continuation of a Task. In short; the compiler knows to look for all await calls and put the rest of the method in a continuation.
The await keyword tells the compiler to call the Task.GetAwaiter() method on the Task ( and basically subscribe to the INotifyCompletion and ICriticalNotifyCompletion) to signal the continuation in the method.
And this I wanted to add just incase you weren't aware. If you do have more than one task that you want to await but would rather await one task as if they were all one then you can do that with Task.WhenAll() So instead of:
var taskA = DoTaskAsync();
var taskB = DoTaskAsync();
var taskC = DoTaskAsync();
await taskA;
await taskB;
await taskC;
You could write it a little cleaner like so:
var taskA = DoTaskAsync();
var taskB = DoTaskAsync();
var taskC = DoTaskAsync();
await Task.WhenAll(taskA, taskB, taskC);
And there are more ways of doing this sort of thing built in; just explore it.

C# wait DLL async method to finish

I have a DLL which has public Task<> method which returns return Task.Factory.StartNew(() => ...). I am calling it within a program and I want the program to wait for the execution of the task to finish before it continues doing other things. I've added Thread.Sleep(6000) to the DLL to simulate longer execution.
When I'm calling it like this
var invokedTask = myMethod.Invoke(Activator.CreateInstance(myClass), myParams);
It just continues with execution (as expected). But then I tried this:
var invokedTask = Task.Factory.StartNew(() => myMethod.Invoke(Activator.CreateInstance(myClass), myParams));
invokedTask.Wait();
And it doesn't work. How can I make it wait from outside of DLL?
Just Wait for the task that is being returned - don't spin up another Task just to call the original method:
var invokedTask = (Task)myMethod.Invoke(Activator.CreateInstance(myClass), myParams);
invokedTask.Wait();
I think the calling method must have the async keyword in the definition:
async void (or Task) MyCaller()
{
await Task.Factory.StartNew(() => myMethod.Invoke(Activator.CreateInstance(myClass), myParams));
}
void or Task depends on which context you are in.
When you wait() a Task.Factory.StartNew() the result is a Task
Therefore you have to call wait() two times or you can use await operator.
Therefore you can do the following.
var invokedTask = Task.Factory.StartNew(() => myMethod.Invoke(Activator.CreateInstance(myClass), myParams));
var result=await await invokedTask;
Or you can do the following
var invokedTask = Task.Factory.StartNew(() => myMethod.Invoke(Activator.CreateInstance(myClass), myParams));
invokedTask.Wait();
var resultTask=invokedTask.Result;
resultTask.Wait();
var result=resultTask.Result;
However from the question you have posted, it looks like your myMethod.Invoke() returns Task.Factor.StartNew() therefore I would like you to try
var result =await await myMethod.Invoke(Activator.CreateInstance(myClass), myParams);
However it is a bad practice to use Wait() and then Result() as it block the current thread.
Therefore I would like you to use await.
This example may help:
public class MagicClass
{
private int magicBaseValue;
public MagicClass()
{
magicBaseValue = 9;
}
public Task<int> ItsMagic(int preMagic)
{
return Task.Factory.StartNew(() => preMagic * magicBaseValue);
}
}
public class TestMethodInfo
{
public static void Main()
{
// Get the ItsMagic method and invoke with a parameter value of 100
Type magicType = typeof(MagicClass);
MethodInfo magicMethod = magicType.GetMethod("ItsMagic");
var magicValue = ((Task<int>)(magicMethod.Invoke(Activator.CreateInstance(typeof(MagicClass)), new object[] { 100 }))).Result;
Console.WriteLine("MethodInfo.Invoke() Example\n");
Console.WriteLine("MagicClass.ItsMagic() returned: {0}", magicValue.ToString());
Console.ReadKey();
}
}
You can cast your Invoke as a Task<> and then get the Result. This will wait until the method is done executing.

How do I create a Task that uses await inside the body that behaves the same as the synchronous version when Wait is called?

I have some code that creates a task that does some slow work like this:
public static Task wait1()
{
return new Task(() =>
{
Console.WriteLine("Waiting...");
Thread.Sleep(10000);
Console.WriteLine("Done!");
});
}
In the real implementation, the Thread.Sleep will actually be a web service call. I would like to change the body of the method can use await (so it does not consume a thread during the network access/sleep). My first attempt (based on shotgun-debugging the compile errors) was this:
public static Task wait2()
{
return new Task(async () =>
{
Console.WriteLine("Waiting...");
await Task.Delay(10000);
Console.WriteLine("Done!");
});
}
However; this task doesn't seem to behave the same as the first one, because when I call .Wait() on it; it returns immediately.
Below is a full sample (console app) showing the differences (the app will end immediately when the second task starts).
What do I need to do so that I can call Start and Wait on a Task which happens to have code using await inside it? The tasks are queued and executed later by an agent, so it's vital that the task is not auto-started.
class Program
{
static void Main(string[] args)
{
var w1 = wait1();
w1.Start();
w1.Wait(); // This waits 110 seconds
var w2 = wait2();
w2.Start();
w2.Wait(); // This returns immediately
}
public static Task wait1()
{
return new Task(() =>
{
Console.WriteLine("Waiting...");
Thread.Sleep(10000);
Console.WriteLine("Done!");
});
}
public static Task wait2()
{
return new Task(async () =>
{
Console.WriteLine("Waiting...");
await Task.Delay(10000);
Console.WriteLine("Done!");
});
}
}
It seems like this isn't possible! See alexm's answer here:
Tasks returned by async methods are always hot i.e. they are created in Running state.
:-(
I've worked around this by making my agent queue Func<Task>s instead, and the overload that receives a task simply queues () => task. Then; when de-queing a task, I check if it's not running, and if so, start it:
var currentTask = currentTaskFunction();
if (currentTask.Status == TaskStatus.Created)
currentTask.Start();
It seems a little clunky to have to do this (if this simple workaround works; why the original restriction on async methods always being created hot?), but it seems to work for me :-)
You could write this as:
public static async Task Wait2()
{
Console.WriteLine("Waiting...");
await Task.Delay(10000);
Console.WriteLine("Done!");
}
In general, it's rarely a good idea to ever use new Task or new Task<T>. If you must launch a task using the ThreadPool instead of using the async/await language support to compose one, you should use Task.Run to start the task. This will schedule the task to run (which is important, tasks should always be "hot" by conventions).
Note that doing this will make it so you don't have to call Task.Start, as well.
To help you understand this realize that async / await essentially does not create a new thread but rather it schedules that portion of code to be ran at an available point in time.
When you create the new Task(async () => ...) you have a task that run an async method. When that inner async method hits an await the 'new Task' is considered complete because the rest of it has been scheduled. To help you understand better place some code (a lot if wanted) in the 'new Task' before the await command. It will all execute before the application terminates and once await is reached that task will believe it has completed. It then returns and exits the application.
The best way to avoid this is to not place any task or async methods inside of your task.
Remove the async keyword and the await keyword from the method and it will work as expected.
This is the same as creating a callback if you're familiar with that.
void MethodAsync(Action callback)
{
//...some code
callback?.Invoke();
}
//using this looks like this.
MethodAsync(() => { /*code to run when complete */});
//This is the same as
Task MethodAsync()
{
//... some code here
}
//using it
await MethodAsync();
/*code to run when complete */
The thing to understand is that you're creating a new task within a task basically. So the inner 'callback' is being created at the await keyword.
You're code looks like this..
void MethodAsync(Action callback)
{
//some code to run
callback?.Invoke(); // <- this is the await keyword
//more code to run.. which happens after we run whoever is
//waiting on callback
}
There's code missing obviously. If this doesn't make sense please feel free to contact me and I'll assist. async / await (meant to make things simpler) is a beast to wrap your head around at first. Afterward you get it then it'll probably be your favorite thing in c# since linq. :P
Try this:
public async static Task wait2()
{
Console.WriteLine("Waiting...");
await Task.Delay(2000);
Console.WriteLine("Done!");
}
But we aware that the task is already started so you don't have to call start:
var w2 = wait2();
//w2.Start();
w2.Wait();
I think the problem with your wait2 function is that is creating 2 task, the one in new Task(...) and another in Task.Delay(). You are waiting for the first one, but you are not waiting for the inner one.

Categories

Resources