I'm trying to write a function that will test some condition and return a value, but if the condition isn't satisfied, it will wait and then try again. I could, of course, just throw in a Thread.Sleep, but I thought I ought to be able to pull this off with tasks and asynch / await, but I can't quite hit of the right syntax to make this work. For example:
public async Task<T> Get<T>(TimeSpan waittime)
{
if (someCondition)
{
return SomeFunctionThatReturnsValue<T>();
}
else
{
return await Get<T>(waitime);
}
}
Works, but doesn't have any delay (obviously), so I've tried multiple variations like this:
public async Task<T> Get<T>(TimeSpan waittime)
{
if (someCondition)
{
return SomeFunctionThatReturnsValue<T>();
}
else
{
return await Task.Delay(waittime).ContinueWith(t => Get<T>(waitime));
}
}
But this give me the compile time error:
Error 52 Since this is an async method, the return expression must be of type 'T' rather than 'Task<T>'
I can change the last return to this:
return await Task.Delay(waittime).ContinueWith(t => Get<T>(waittime).Result);
And it compiles, but that doesn't seem exactly right either.
Since you want your method to be asyncrhonous, when you want to get the result of a Task you should use await, not Result, so that the action is performed asynchronously, so you can write that operation as:
return await await Task.Delay(waittime).ContinueWith(t => Get<T>(waitime));
Alternatively, whenever you have two awaits you can use Unwrap instead; it's not really better or worse; it's equivalent:
return await Task.Delay(waittime).ContinueWith(t => Get<T>(waitime)).Unwrap();
Note that by using Unwrap you could also make the method not be async and not await it because Unwrap is already doing the job of turning your Task<Task<T>> into a Task<T>.
Of course, you generally shouldn't be using ContinueWith in an async method for the most part, you should simply be using await to attach continuations to your tasks:
await Task.Delay(waittime)
return Get<T>(waitime);
It's also worth noting that you should really be using a while loop here, rather than using recursion, particularly because you have an async method which means building another state machine for every single recursive invocation.
Related
I have a chain of task-returning methods, all returning some Task<SomeResponse<T>>. SomeResponse<T> is a generic response class exposing properties like whether the response was successful (IsSuccess), if it's successful a T Data property containing the returning object, and if not an accompanying error message.
Let's assume I have 3 such methods (all of them returning SomeResponse<T>). I only want to keep executing the tasks one-by-one until one of them fails or all of them succeed. The flow would look like this:
var first = await firtTask(someParam);
if (!first.IsSuccess) return first;
var second = await secondTask(first.Data);
if (!second.IsSuccess) return second;
var third = await thirdTask(second.Data);
return third; // doesn't matter if it succeeded or not as it's the last one, no need to check.
My issue here is that the SomeResponse<T> of each call needs to be validated for success before proceeding to the next await, which adds a lot of repetitive validation code. Checking if each task completed successfully is not enough, as I then have to inspect it's SomeResponse<T>.IsSuccess property before proceeding to the next task.
I tried creating an extension method on top of Task<SomeResponse<T>> for this:
public static Task<SomeResponse<T>> OnSuccessChainAsync<T>(this Task<SomeResponse<T>> startingTask, Func<T, Task<SomeResponse<T>>> continuationTask)
{
// omitting null checks etc
var continuation = startingTask.ContinueWith(
async previousTask =>
{
var response = await previousTask.ConfigureAwait(false);
if (!response.IsSuccess)
{
return response;
}
return await continuationTask(response.Data).ConfigureAwait(false);
}, TaskScheduler.Current);
return continuation.Unwrap();
}
This now allows me to write:
public override Task<SomeResponse<TValue>> AddAsync(TValue someValue)
{
return firstTask(someValue)
.OnSuccessChainAsync(secondTask)
.OnSuccessChainAsync(thirdTask);
}
I'm not sure if I'm heading in the wrong direction here. I am mixing async-await with TPL's ContinueWith, and on top of that I get a VSTHRD003 Avoid awaiting foreign Tasks from my analyzers.
Don't mix the old-style ContinueWith with async/await.
In fact, try and avoid ContinueWith completely: it's horrendously complex with lots of bits of subtle behaviour, half of which you never want to think about and half of which are much more clearly expressed with async/await.
Why not simplify things a bit:
public static async Task<SomeResponse<T>> ExecuteInSequence<T>(
T firstData,
params Func<T, Task<Response<T>>>[] funcs)
{
T data = firstData;
foreach (var func in funcs)
{
var response = await func(data);
if (!response.IsSuccess)
{
return response;
}
data = response.Data;
}
return data;
}
Then you can write:
ExecuteInSequence(someValue, task1, task2, task3);
There's no mixing of anything, no chaining, just a straightforward loop.
If you were going to write this as an extension method on Task<SomeResponse<T>>, I'd still keep everything as awaits:
public static async Task<SomeResponse<T>> OnSuccessChainAsync<T>(
this Task<SomeResponse<T>> startingTask,
Func<T, Task<SomeResponse<T>>> continuationTask)
{
// startingTask will probably have already completed (especially if
// it's one which we created on a previous invocation), in which case
// this await will be synchronous.
var result = await startingTask;
if (!result.IsSuccess)
{
return result;
}
return await continuationTask(result.Data);
}
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.
This question already has answers here:
Why use async and return await, when you can return Task<T> directly?
(9 answers)
How and when to use ‘async’ and ‘await’
(25 answers)
Closed 3 years ago.
I was looking at how to use async await, but I do not quite get it when we have multiple methods invoking each other. Should we always use await or should we only use await when we are actually ready to use the result?
So for example should we do it like this:
async Task<string[]> FooAsync()
{
var info = await Func1();
return info.split('.');
}
async Task<string> Func1()
{
return await Func2();
}
async Task<string> Func2()
{
return await tcpClient.ReadStringAsync();
}
Or like this:
async Task<string[]> FooAsync()
{
var info = await Func1();
return info.split('.');
}
Task<string> Func1()
{
return Func2();
}
Task<string> Func2()
{
return tcpClient.ReadStringAsync();
}
Per example 1, should we always use await in every method?
Or
Per example 2 should we only use await on the top-most method when we start using the result?
Every-time you call await it creates a lump of code to bundle up variables, captures the synchronization context (if applicable) and create a continuation into an IAsyncStateMachine.
Essentially, returning a Task without the async keyword will give you a small run-time efficiency and save you a bunch of CIL. Do note that the Async feature in .NET also has many optimizations already. Also note (and importantly) that returning a Task in a using statement will likely throw an Already Disposed Exception.
You can compare the CIL and plumbing differences here
Forwarded Task
Async Method
So if your method is just forwarding a Task and not wanting anything from it, you could easily just drop the async keyword and return the Task directly.
More-so, there are times when we do more than just forwarding and there is branching involved. This is where, Task.FromResult and Task.CompletedTask come into play to help deal with the logic of what may arise in a method. I.e If you want to give a result (there and then), or return a Task that is completed (respectively).
Lastly, the Async and Await Pattern has subtle differences when dealing with Exceptions. If you are returning a Task, you can use Task.FromException<T> to pop any exception on the the returned Task like an async method would normally do.
Nonsensical example
public Task<int> DoSomethingAsync(int someValue)
{
try
{
if (someValue == 1)
return Task.FromResult(3); // Return a completed task
return MyAsyncMethod(); // Return a task
}
catch (Exception e)
{
return Task.FromException<int>(e); // Place exception on the task
}
}
In short, if you don't quite understand what is going on, just await it; the overhead will be minimal. However, if you understand the subtitles of how to return a task result, a completed task, placing an exception on a task, or just forwarding. You can save your self some CIL and give your code a small performance gain by dropping the async keyword returning a task directly and bypassing the IAsyncStateMachine.
At about this time, I would look up the Stack Overflow user and author Stephen Cleary, and Mr. Parallel Stephen Toub. They have a plethora of blogs and books dedicated solely to the Async and Await Pattern, all the pitfalls, coding etiquette and lots more information you will surely find interesting.
Both options are legit and each option has own scenarios where it is more effective then another.
Of course always use await when you want to handle result of the asynchronous method or handle possible exception in current method
public async Task Execute()
{
try
{
await RunAsync();
}
catch (Exception ex)
{
// Handle thrown exception
}
}
If you don't use result of asynchronous method in current method - return the Task. This approach will delay state machine creation to the caller or where ever final task will be awaited. As pointed in the comments can make execution little bit more effective.
But there are scenarios where you must await for the task, even you do nothing with result and don't want handle possible exceptions
public Task<Entity> GetEntity(int id)
{
using (var context = _contextFactory.Create())
{
return context.Entities.FindAsync(id);
}
}
In the scenario above, FindAsync can return not completed task and this task will be returned straight away to the caller and dispose context object created within using statement.
Later when caller will "await" for the task exception will be thrown because it will try to use already disposed object(context).
public async Task<Entity> GetEntity(int id)
{
using (var context = _contextFactory.Create())
{
return await context.Entities.FindAsync(id);
}
}
And traditionally answers about Async Await must include link to Stephen Cleary's blog
Eliding Async and Await
Await is a sequencing feature which allows the caller to receive the result of an async method and do something with it. If you do not need to process the result of an async function, you do not have to await it.
In your example Func1() and Func2() do no process the return values of the called async functions, so it is fine not to await them.
When you use await the code will wait for the async function to finish. This should be done when you need a value from an async function, like this case:
int salary = await CalculateSalary();
...
async Task<int> CalculateSalary()
{
//Start high cpu usage task
...
//End high cpu usage task
return salary;
}
If you hadn't use the the await this would happen:
int salary = CalculateSalary().Result;
...
async Task<int> CalculateSalary()
{
//Start high cpu usage task
... //In some line of code the function finishes returning null because we didn't wait the function to finish
return salary; //This never runs
}
Await means, wait this async function to finish.
Use it to your needs, your case 1 and 2 would produce the same result, as long as you await when you assign the info value the code will be safe.
Source: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/index
I believe the 2nd one will do because await is expecting a return value.
Since it is waiting for the Func1() to return a value, Func1() is already executing Func2() which is returning a value.
What is the difference between
ResultType result = await Task.Run(() => GetResultAsync())
and
ResultType result = await Task.Run(async() => await GetResultAsync())
I would speculate that the former would fire and forget GetResultAsync(), since it is not awaited, but then how does it get the result? I am surprised that the return type of the formerTask.Run is Task<ResultType> and not Task<Task<ResultType>>.
Both do the same from perspective of result. In both cases the overload Task.Run<TResult>(Func<Task<TResult>> function) is used which internally unwraps the task - that's why result is Task<ResultType>. The difference between them is equiavalent to the difference between
static Task<T> Compute()
{
return GetAsyncResult();
}
and
static async Task<T> Compute()
{
return await GetAsyncResult();
}
In the first case the promise is just passed back to the caller, while in the second the state machine is built by compiler around the Compute method.
In the first line the 'Task.Run' you start, immediately returns the result of 'GetResultAsync'. That result however, is a Task that can be awaited (by your 'await').
So, you actually 'await' the 'GetResultAsync' method.
In the second line, you start a Task that does not return immediately, but waits till 'GetResultAsync' (called asynchronously) is finished. The returntype of your Task is 'ResultType'.
So you 'await' your own Task, that in its turn will only return after awaiting the 'GetResultAsync' method.
In the end, they both accomplish the same result, but in a slightly different manner.
void A()
{
foreach (var document in documents)
{
var res = records.BulkWriteAsync(operationList, writeOptions); // res is Task<BulkWriteResult<JobInfoRecord>>
}
}
After foreach I would like to wait the result of all BulkWriteAsync, how to do this? I don't want to mark A() as async and do the following
await records.BulkWriteAsync(operationList, writeOptions);
Is it good solution?
void A()
{
var tasks = new List<Task<BulkWriteResult<JobInfoRecord>>>();
foreach (var document in documents)
{
var task = records.BulkWriteAsync(operationList, writeOptions);
tasks.Add(task);
}
Task.WaitAll(tasks.ToArray());
}
I call A() in try catch if I will mark public async void A() as async I never be in catch
Well, first you want a Task that represents all the operations. The simplest way to do this is with a bit of LINQ:
Task.WhenAll(documents.Select(i => records.BulkWriteAsync(...)));
Then, you ideally want to await that task. If that isn't possible, you can try
task.GetAwaiter().GetResult();
However, make sure that none of the tasks have thread affinity - that's a great way to get a deadlock. Waiting for a task on the UI thread while the task itself needs the UI thread is a typical example.
The whole point of await is that it allows you to handle asynchronous code as if it were synchronous. So from the outside, it appears as if you never left the method until you actually get to a return (or the end of the method). For this to work, however, your method must return a Task (or Task<T>), and the callee must await your method in turn.
So a code like this:
try
{
tasks = Task.WhenAll(documents.Select(i => ...));
await tasks;
}
catch (Exception ex)
{
// Handle the exception
}
will appear to run completely synchronously, and all exceptions will be handled as usual (though since we're using Task.WhenAll, some will be wrapped in AggregateException).
However, this isn't actually possible to handle with the way .NET and C# is built, so the C# compiler cheats - await is basically a return that gives you a promise of the result you'll get in the future. And when that happens, the control returns back to where the await left the last time. Task is that promise - if you use async void, there's no way for the callee to know what's happening, and it has no option but to continue as if the asynchronous method was a run-and-forget method. If you use async Task, you can await the async method and everything "feels" synchronous again. Don't break the chain, and the illusion is perfect :)