Create async Task<T> without run - c#

How can I create a async Task but not run it right away?
private static async Task<string> GetString()
{
await Task.Delay(5000);
return "Finish";
}
Task<string> str = GetString();
This immediately starts the task.

If you want dereferred excecution use Func.
private static Func<Task<string>> GetStringFunc()
=> GetString;
Thus:
var deferred = GetStringFunc();
/*whatever*/
var task = deferred();
Update: please have a look at Lazy<T>.

You can create a cold Task by wrapping it in another Task.
The outer task creates the inner one without starting it.
//. If you don't call Start() and then await
//. Your code will never fire
public static async RunMe() {
var coldTask = new Task<Task<string>>(GetString);
// To start the task
coldTask.Start();
// And then let it finish
await coldTask;
}
// sharplab.io shows how C# compiles the async keyword
//. into a state machine that creates the inner task without starting it.

Related

C# wait for a function that returns void to finish a System.NET.WebClient.DownloadFileAsync() while still keeping an active WinForms UI [duplicate]

How can I wait for a void async method to finish its job?
for example, I have a function like below:
async void LoadBlahBlah()
{
await blah();
...
}
now I want to make sure that everything has been loaded before continuing somewhere else.
Best practice is to mark function async void only if it is fire and forget method, if you want to await on, you should mark it as async Task.
In case if you still want to await, then wrap it like so await Task.Run(() => blah())
If you can change the signature of your function to async Task then you can use the code presented here
The best solution is to use async Task. You should avoid async void for several reasons, one of which is composability.
If the method cannot be made to return Task (e.g., it's an event handler), then you can use SemaphoreSlim to have the method signal when it is about to exit. Consider doing this in a finally block.
You don't really need to do anything manually, await keyword pauses the function execution until blah() returns.
private async void SomeFunction()
{
var x = await LoadBlahBlah(); <- Function is not paused
//rest of the code get's executed even if LoadBlahBlah() is still executing
}
private async Task<T> LoadBlahBlah()
{
await DoStuff(); <- function is paused
await DoMoreStuff();
}
T is type of object blah() returns
You can't really await a void function so LoadBlahBlah() cannot be void
I know this is an old question, but this is still a problem I keep walking into, and yet there is still no clear solution to do this correctly when using async/await in an async void signature method.
However, I noticed that .Wait() is working properly inside the void method.
and since async void and void have the same signature, you might need to do the following.
void LoadBlahBlah()
{
blah().Wait(); //this blocks
}
Confusingly enough async/await does not block on the next code.
async void LoadBlahBlah()
{
await blah(); //this does not block
}
When you decompile your code, my guess is that async void creates an internal Task (just like async Task), but since the signature does not support to return that internal Tasks
this means that internally the async void method will still be able to "await" internally async methods. but externally unable to know when the internal Task is complete.
So my conclusion is that async void is working as intended, and if you need feedback from the internal Task, then you need to use the async Task signature instead.
hopefully my rambling makes sense to anybody also looking for answers.
Edit:
I made some example code and decompiled it to see what is actually going on.
static async void Test()
{
await Task.Delay(5000);
}
static async Task TestAsync()
{
await Task.Delay(5000);
}
Turns into (edit: I know that the body code is not here but in the statemachines, but the statemachines was basically identical, so I didn't bother adding them)
private static void Test()
{
<Test>d__1 stateMachine = new <Test>d__1();
stateMachine.<>t__builder = AsyncVoidMethodBuilder.Create();
stateMachine.<>1__state = -1;
AsyncVoidMethodBuilder <>t__builder = stateMachine.<>t__builder;
<>t__builder.Start(ref stateMachine);
}
private static Task TestAsync()
{
<TestAsync>d__2 stateMachine = new <TestAsync>d__2();
stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
stateMachine.<>1__state = -1;
AsyncTaskMethodBuilder <>t__builder = stateMachine.<>t__builder;
<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
neither AsyncVoidMethodBuilder or AsyncTaskMethodBuilder actually have any code in the Start method that would hint of them to block, and would always run asynchronously after they are started.
meaning without the returning Task, there would be no way to check if it is complete.
as expected, it only starts the Task running async, and then it continues in the code.
and the async Task, first it starts the Task, and then it returns it.
so I guess my answer would be to never use async void, if you need to know when the task is done, that is what async Task is for.
do a AutoResetEvent, call the function then wait on AutoResetEvent and then set it inside async void when you know it is done.
You can also wait on a Task that returns from your void async
You can simply change the return type to Task and call await Task.CompletedTask at the end of the function, e.g:
async Task MyFunction() {
await AnotherFunction();
await Task.CompletedTask;
}
I find this simpler than wrapping the whole function body in a call to Task.Run(() => { ... });.
I've read all the solutions of the thread and it's really complicated... The easiest solution is to return something like a bool:
async bool LoadBlahBlah()
{
await blah();
return true;
}
It's not mandatory to store or chekc the return value. You can juste do:
await LoadBlahBlah();
... and you can return false if something goes wrong.

await on task to finish, with operations after the 'await'

I know I may be downvoted but apparently I just don't understand async-await enough and the questions/answer I found, and the articles I found, didn't help me to find an answer for this question:
How can I make "2" to be printed out? Or actually, WHY doesn't 2 gets printed out, both in await t and in t.Wait() ?:
static Task t;
public static async void Main()
{
Console.WriteLine("Hello World");
t = GenerateTask();
await t;
//t.Wait();
Console.WriteLine("Finished");
}
public static Task GenerateTask()
{
var res = new Task(async () =>
{
Console.WriteLine("1");
await Task.Delay(10000);
Console.WriteLine("2");
});
res.Start();
return res;
}
Edit: I'm creating a task and returning it cause in real-life I need to await on this task later on, from a different method.
Edit2: await Task.Delay is just a placeholder for a real-life await on a different function.
Printing '2'
The 2 is actually printed, 10 seconds after 1 is printed. You can observe this if you add Console.ReadLine(); after printing 'Finished'.
The output is
Hello World
1
Finished
2
What is happening?
When you await t (which is res in GenerateTask method) you are awaiting the created Task and not the task that res created.
How to fix (fancy way)
You will need to await both the outer task and inner task. To be able to await the inner task you need to expose it. To expose it you need to change the type of the task from Task to Task<Task> and the return type from Task to Task<Task>.
It could look something like this:
public static async Task Main()
{
Console.WriteLine("Hello World");
var outerTask = GenerateTask();
var innerTask = await outerTask; // what you have
await innerTask; // extra await
Console.WriteLine("Finished");
Console.ReadLine();
}
public static Task<Task> GenerateTask() // returns Task<Task>, not Task
{
var res = new Task<Task>(async () => // creates Task<Task>, not Task
{
Console.WriteLine("1");
await Task.Delay(TimeSpan.FromSeconds(10));
Console.WriteLine("2");
});
res.Start();
return res;
}
The output now is:
Hello World
1
2
Finished
How to fix (easy way)
The outer task is not needed.
public static async Task Main()
{
Console.WriteLine("Hello World");
var t = GenerateTask();
await t;
Console.WriteLine("Finished");
Console.ReadLine();
}
public static async Task GenerateTask()
{
Console.WriteLine("1");
await Task.Delay(TimeSpan.FromSeconds(10));
Console.WriteLine("2");
}
It looks like it's because the constructor to new Task only takes some form of an Action (So the Task never gets returned even though it's async). So essentially what you're doing is an Async void with your delegate. Your await Task.Delay(10000) is returning and the action is considered 'done'.
You can see this if you change the await Task.Delay(10000) to Task.Delay(10000).Wait() and remove the async from the delegate.
On another note though, I've never personally seen or used new Task before. Task.Run() is a much more standard way to do it, and it'll allow for the await to be used. Also means you don't have to call Start() yourself.
Also you might already know this but, in this specific case you don't need a new task at all. You can just do this:
public static async Task GenerateTask()
{
Console.WriteLine("1");
await Task.Delay(10000);
Console.WriteLine("2");
}
Regarding your edits
Replacing your GenerateTask with what I wrote should do what you want. The async/await will turn your method into a Task that has started execution. This is exactly what you are trying to do so I'm not quite sure what you are asking with your edits.
The task returned from GenerateTask can be awaited whenever you want, or not awaited at all. You should almost never need to do new Task(). The only reason I can think is if you wanted to delay execution of the task until later, but there would be better ways around it rather than calling new Task().
If you use the way I showed in your real-life situation, let me know what doesn't work about it and I'll be happy to help.
You should use Task.Run() rather than creating a Task directly:
public static Task GenerateTask()
{
return Task.Run(async () =>
{
Console.WriteLine("1");
await Task.Delay(10000);
Console.WriteLine("2");
});
}
Task.Start() doesn't work because it doesn't understand async delegates, and the returned task just represents the beginning of the task.
Note that you can't fix this by using Task.Factory.StartNew() either, for the same reason.
See Stephen Cleary's blog post on this issue, from which I quote:
[Task.Factory.StartNew()] Does not understand async delegates. This is actually the same as
point 1 in the reasons why you would want to use StartNew. The problem
is that when you pass an async delegate to StartNew, it’s natural to
assume that the returned task represents that delegate. However, since
StartNew does not understand async delegates, what that task actually
represents is just the beginning of that delegate. This is one of the
first pitfalls that coders encounter when using StartNew in async
code.
These comments also apply to the Task constructor, which also doesn't understand async delegates.
However, it's important to note that if you are already awaiting in the code and you don't need to parallelise some compute-bound code, you don't need to create a new task at all - just using the code in your Task.Run() on its own will do.

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.

Adding List of tasks without executing

I have a method which returns a task, which I want to call multiple times and wait for any 1 of them to be successful. The issue I am facing is as soon as I add the task to the List, it executes and since I added delay to simulate the work, it just block there.
Is there a way to add the the tasks to the list without really executing it and let whenAny execute the tasks.
The below code is from Linqpad editor.
async void Main()
{
var t = new Test();
List<Task<int>> tasks = new List<Task<int>>();
for( int i =0; i < 5; i++)
{
tasks.Add(t.Getdata());
}
var result = await Task.WhenAny(tasks);
result.Dump();
}
public class Test
{
public Task<int> Getdata()
{
"In Getdata method".Dump();
Task.Delay(90000).Wait();
return Task.FromResult(10);
}
}
Update :: Below one makes it clear, I was under the impression that if GetData makes a call to network it will get blocked during the time it actually completes.
async void Main()
{
OverNetwork t = new OverNetwork();
List<Task<string>> websitesContentTask = new List<Task<string>>();
websitesContentTask.Add(t.GetData("http://www.linqpad.net"));
websitesContentTask.Add(t.GetData("http://csharpindepth.com"));
websitesContentTask.Add(t.GetData("http://www.albahari.com/nutshell/"));
Task<string> completedTask = await Task.WhenAny(websitesContentTask);
string output = await completedTask;
Console.WriteLine(output);
}
public class OverNetwork
{
private HttpClient client = new HttpClient();
public Task<string> GetData(string uri)
{
return client.GetStringAsync(uri);
}
}
since I added delay to simulate the work, it just block there
Actually, your problem is that your code is calling Wait, which blocks the current thread until the delay is completed.
To properly use Task.Delay, you should use await:
public async Task<int> Getdata()
{
"In Getdata method".Dump();
await Task.Delay(90000);
return 10;
}
Is there a way to add the the tasks to the list without really executing it and let whenAny execute the tasks.
No. WhenAny never executes tasks. Ever.
It's possible to build a list of asynchronous delegates, i.e., a List<Func<Task>> and execute them later, but I don't think that's what you're really looking for.
There are multiple tasks in your Getdata method. First does delay, but you are returning finished task which returned 10. Try to change your code like this
return Task.Delay(90000).ContinueWith(t => 10)

C# tasks are executed before Task.WhenAll

Why the tasks are executed before Task.WhenAll??
If you see here, from the below code snippet, first Console.WriteLine("This should be written first.."); should be printed because I am awaiting the tasks beneath to it..
But if you see the output result, the Tasks method result is being printed before the above statement. Ideally, the tasks method should be executed when I await them, but it seems that- the tasks methods are executed the moment I add them in tasks list. Why is it so?
Would you please do let me know why is this happening??
Code:
public static async Task Test()
{
var tasks = new List<Task>();
tasks.Add(PrintNumber(1));
tasks.Add(PrintNumber(2));
tasks.Add(PrintNumber(3));
Console.WriteLine("This should be written first..");
// This should be printed last..
await Task.WhenAll(tasks);
}
public static async Task PrintNumber(int number)
{
await Task.FromResult(0);
Console.WriteLine(number);
}
Output
When you call an async method you get a "hot" task in return. That means that the task already started running (and maybe even completed) before you get to await them. That means that it's quite possible for the tasks to run and complete before the call to Task.WhenAll.
In your case however, while the PrintNumber is marked async it isn't asynchronous at all since you're using Task.FromResult. The synchronous part of an asynchronous method (which is the part until you await an asynchronous task) is always executed synchronously on the calling thread and is done before the call returns. When you use Task.FromResult you get a completed task so all your method is just the synchronous part and is completed before the call returns.
When you await a completed task (as is created by Task.FromResult, it completes synchronously. This means that in your example, nothing is actually happening asynchronously, which explains the order of execution.
If instead, you were to
await Task.Yield();
you'd see output more in line with your expectations.
Task.FromResult won't cause yield and the task will be executed on the same thread. To achieve what you want you can do this:
public static async Task Test()
{
var tasks = new List<Task>();
tasks.Add(PrintNumber(1));
tasks.Add(PrintNumber(2));
tasks.Add(PrintNumber(3));
Console.WriteLine("This should be written first..");
// This should be printed last..
await Task.WhenAll(tasks);
}
public static async Task PrintNumber(int number)
{
await Task.Yield();
Console.WriteLine(number);
}
If you want a Task or tasks to run after something else, its easiest to write your code accordingly.
public static async Task Test()
{
Console.WriteLine("This should be written first..");
// These should be printed last..
await Task.WhenAll(new[]
{
PrintNumber(1),
PrintNumber(2),
PrintNumber(3)
});
}
following on from your comment.
So we have some functions,
async Task<Customer> GetRawCustomer()
{
...
}
async Task<string> GetCity(Customer customer)
{
...
}
async Task<string> GetZipCode(Customer customer)
{
...
}
We could use them like this
var rawCustomer = await GetRawCustomer();
var populationWork = new List<Task>();
Task<string> getCity;
if (string.IsNullOrWhiteSpace(rawCustomer.City))
{
getCity = GetCity(rawCustomer);
populationWork.Add(getCity);
}
Task<string> getZipCode;
if (string.IsNullOrWhiteSpace(rawCustomer.City))
{
getZipCode = GetZipCode(rawCustomer);
populationWork.Add(getZipCode);
}
...
await Task.WhenAll(populationWork);
if (getCity != null)
rawCustomer.City = getCity.Result;
if (getZipCode != null)
rawCustomer.ZipCode = getZipCode.Result;

Categories

Resources