ContinueWith Method - How to understand it exactly? - c#

So i have e.g. this code here:
initialTask.ContinueWith((argument) => { ... });
I understand the second Task is executed once the first one is finished.
I have to provide the second Task with an argument though, which is also of Type Task.
Is this 'argument' the OLD task or is this an entirely new instance?
E.g. when i want to handle a cancellation of the First Task in the Second Task, do i have to call:
initialTask.IsCanceled
or
argument.IsCanceled
?

Is this 'argument' the OLD task or is this an entirely new instance?
Yes, it's a reference to the same Task instance parameter passed as the parameter to .ContinueWith (i.e. "Old") - you can verify this as per below:
var initialTask = Task.Delay(1000);
initialTask.ContinueWith(t2 => {Debug.Assert(t2 == initialTask);}).Wait();
The reason why the task instance is passed in is to allow you to access the completed state and output of the Task. But, before accessing the result of t2, you'll need to see whether it throws an exception (t2.IsFaulted), cancelled (t2.IsCanceled) etc which becomes messy very quickly.
Instead, now that C# supports the async / await syntax, that you should find the code easier to read, and easier to handle exceptions etc, if you rewrite your code as follows:
async Task MyMethod()
{
try
{
var initialResult = await SomeInitialTask();
var secondResult = await SecondTask(initialResult); // instead of .ContinueWith and accessing t2.Result
... etc.
}
catch (Exception ex)
{
// Much easier than checking .IsFaulted on each nested task
}
}

The argument is the old task. It is provided as argument for convenience and efficiency. Without it the lambda would be forced to close over the variable initialTask in the outer scope, and closures have a memory overhead.

Related

How to sequential multilevel async process with C#?

I have a daily scheduler sequential scenario that needs to run every midnight:
Check_Tenant_Expiry and Get its return value (true/false)
Run_Daily_Report (pass the returning value from Check_Tenant_Expiry)
I expect to do Check_Tenant_Expiry and after it completed it will continue with Run_Daily_Report, I use the code below
bool _xxx = await Check_Tenant_Expiry().ContinueWith(t =>
{
Run_Daily_Report(_xxx); // THE WARNING GOES HERE
}, TaskContinuationOptions.OnlyOnRanToCompletion);
public static async Task<bool> Check_Tenant_Expiry()
{
bool _ret = false;
...
...
return await Task.FromResult(_ret);
}
public static async Task Run_Daily_Report()
{ .... }
questions:
Why I got a warning on Run_Daily_Report:
Severity Code Description Project File Line Suppression State
Warning CS4014 Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
I am not sure that I already have correct logic for the sequential multilevel process like first I need to run Check_Tenant_Expiry() until it finished completely and then continue with Run_Daily_Report()
I need advice.
Many thanks in advance
Don
I expect to do Check_Tenant_Expiry and after it completed it will continue with Run_Daily_Report
You shouldn't use ContinueWith for this. ContinueWith is a low-level method with dangerous default behavior. At the very least, you must pass a TaskScheduler. In addition, ContinueWith doesn't understand asynchronous code, so if you pass async code in, you'll also need to use Unwrap.
Instead, you should just use await, which is simpler, more maintainable, and does the right thing by default:
bool _xxx = await Check_Tenant_Expiry();
await Run_Daily_Report(_xxx);
On a side note, this seems suspect:
return await Task.FromResult(_ret);
That's literally a less efficient form of this:
return _ret;
I suspect that the await Task.FromResult was added to avoid a compiler warning telling you that the method will run synchronously. If you were in fact getting that warning, then the proper solution is to either make the method properly asynchronous (not adding an await just to make the warning go away), or to remove the async and leave the method synchronous.
Try this
await Check_Tenant_Expiry().ContinueWith( async (t) =>
{
await Run_Daily_Report();
}, TaskContinuationOptions.OnlyOnRanToCompletion);
You made a function with async keyword, which means you told compiler excute "Run_Daily_Reporty" method by asynchronously. But you didn't execute the method with await keyword, which means It's run by synchronously. That's why compiler told you "it's right?"
Try this
// You must use async keyword when you want to use await keyword in lambda function.
await Check_Tenant_Expiry().ContinueWith(async(t) =>
{
await Run_Daily_Report(t.Result);
}, TaskContinuationOptions.OnlyOnRanToCompletion);
I think you made code the way you wanted to work.
I think you might not know the async/await keywords yet.
They can make your asynchronous code looks like synchronous code that we've been making every day, which means it's way more easy to understand.
How about making code like below. It's going to make the same result with the code you made.
bool result = await Check_Tenant_Expiry();
await Run_Daily_Report(result);

Conversion from async lambda Action into Func<Task>?

We know the async equivalent of Action is Func<Task>.
Therefore we could write:
Func<Task> func = async () =>
{
Console.WriteLine(#"waiting ...");
await Task.Delay(300).ConfigureAwait(false);
Console.WriteLine(#"... finished");
};
But it is also possible to write it as an Action:
Action action = async () =>
{
Console.WriteLine(#"waiting ...");
await Task.Delay(300).ConfigureAwait(false);
Console.WriteLine(#"... finished");
};
This is syntactically correct.
How is it possible to convert Action action into Func<Task> func?
I think that the second snippet is similar to async void - just anonymous. You really should not use them except for some edge cases like WinForms event handlers..
The compiler manages the returned Task for you and puts it into default thread pool and runs continuations on some selected SynchroContext that is "known to be OK".. I don't remember the rest.. check the gory details of async-void and you will hit articles on why you shouldn't use it except for when absolutely necessary. for example:
Reasonably-looking article I found on google
simple excellent description here on Stack Overflow
Note for example differences in exception handling..
Aah, and I forgot to answer: If that's really async void then you cannot convert. Simply - the returned Task is gone and you can't obtain it. The Action you've got is something like:
Action action = () =>
{
Func<Task> yourRealTask = async () =>
{
Console.WriteLine(#"waiting ...");
await Task.Delay(300).ConfigureAwait(false);
Console.WriteLine(#"... finished");
};
// ** some compiler-generated code to register/run the task somewhere
// ** so it will be handled properly instea of being lost due to not
// ** returning the Task to the caller
return;
}
so, effectively, the yourRealTask is not obtainable.. with some luck you may hack it out of some closure via reflection, but.. don't do that. Just use Func<Task>.
The first case will create a normal Task factory.
The second will create a fire-and-forget async-void method, which is indeed used more rarely.
Since compiler is so neat, it can create both from a single anonymous method, and it's up to the programmer to decide which one he needs.

How to create a Task of an async Task method to catch the exceptions?

I have a task that is looping reading on a socket:
private async void readLoop() {
while (!cts.IsCancelRequested()) {
await socket.ReceiveAsync(data, ...);
doWork(data);
}
}
And since the task need not run as soon as it is created, I'm using the Task constructor, rather than Task.Run.
private Task readTask = new Task(readLoop, cts, LongRunning);
// when the task need to run:
readTask.Start()
At this point it works fine, except that when the task need to finish, when I call readTask.Wait() or await readTask, the exceptions happened in ReceiveAsync or doWork are not attached to the readTask. That means even there was exceptions, readTask.Status is RunToComplete and readTask.Exception is null. Accord. to the docs, this is due to the async method returns void, but when I tried this:
private async Task readLoop() {...}
It won't compile:
error CS0407: 'Task WebSocketInitiator.readLoop()' has the wrong return type
So is there anyway to make the task start at a later time and at the same time have it keep track of exceptions happened in the task?
A minimal test case to show the problem: https://dotnetfiddle.net/JIfDIn
If I understand you correctly you want to postpone running the Task until it is needed but you want to keep the creation in a constructor. That is fine, and there is a pattern used for these kind of situations. It's called Lazy.
However, Lazy isn't async. Stephen Taub has however made an async implementation called AsyncLazy.
The reason why you got the error message that you got was because you didn't specify the return value for the outer Task that you created. Also you need to return foos value. If you wrap the call in a lambda which returns the inner Task you can get it though, as such:
var task1 = new Task<Task>(async () => await foo(),
CancellationToken.None, TaskCreationOptions.LongRunning);
task1.Start();
When you await it however you would await the outer task and not the task that it returns. Thus you need to Unwrap it:
task1.Unwrap().Wait();
This way you would catch the exception. However, this is probably not the best way, since the whole reason to use Task.Run, async and await was to avoid these constructs.
In conclusion:
Go for AsyncLazy if you need to postpone the calling of your Task
Don't call the Task constructor
Use Task.Run
And since the task need not run as soon as it is created, I'm using the Task constructor, rather than Task.Run.
You should never use the task constructor. It has literally no rational use cases at all.
In your case, it sounds like you don't need a delegate or lazy-initialization, or anything like that; since your members and methods are private, it would make just as much sense to assign the task member at the time it executes:
private async Task readLoop();
// when the task needs to run:
readTask = Task.Run(() => readLoop());
However, if you do need to represent some code to run in the future and not now, then you want a delegate. In this case, an asynchronous delegate: Func<Task>:
Func<Task> func = () => Task.Run(() => readLoop());
...
Task task = func();

async function never executed why in c# with quartz task backgrounder in c# [duplicate]

I have a multi-tier .Net 4.5 application calling a method using C#'s new async and await keywords that just hangs and I can't see why.
At the bottom I have an async method that extents our database utility OurDBConn (basically a wrapper for the underlying DBConnection and DBCommand objects):
public static async Task<T> ExecuteAsync<T>(this OurDBConn dataSource, Func<OurDBConn, T> function)
{
string connectionString = dataSource.ConnectionString;
// Start the SQL and pass back to the caller until finished
T result = await Task.Run(
() =>
{
// Copy the SQL connection so that we don't get two commands running at the same time on the same open connection
using (var ds = new OurDBConn(connectionString))
{
return function(ds);
}
});
return result;
}
Then I have a mid level async method that calls this to get some slow running totals:
public static async Task<ResultClass> GetTotalAsync( ... )
{
var result = await this.DBConnection.ExecuteAsync<ResultClass>(
ds => ds.Execute("select slow running data into result"));
return result;
}
Finally I have a UI method (an MVC action) that runs synchronously:
Task<ResultClass> asyncTask = midLevelClass.GetTotalAsync(...);
// do other stuff that takes a few seconds
ResultClass slowTotal = asyncTask.Result;
The problem is that it hangs on that last line forever. It does the same thing if I call asyncTask.Wait(). If I run the slow SQL method directly it takes about 4 seconds.
The behaviour I'm expecting is that when it gets to asyncTask.Result, if it's not finished it should wait until it is, and once it is it should return the result.
If I step through with a debugger the SQL statement completes and the lambda function finishes, but the return result; line of GetTotalAsync is never reached.
Any idea what I'm doing wrong?
Any suggestions to where I need to investigate in order to fix this?
Could this be a deadlock somewhere, and if so is there any direct way to find it?
Yep, that's a deadlock all right. And a common mistake with the TPL, so don't feel bad.
When you write await foo, the runtime, by default, schedules the continuation of the function on the same SynchronizationContext that the method started on. In English, let's say you called your ExecuteAsync from the UI thread. Your query runs on the threadpool thread (because you called Task.Run), but you then await the result. This means that the runtime will schedule your "return result;" line to run back on the UI thread, rather than scheduling it back to the threadpool.
So how does this deadlock? Imagine you just have this code:
var task = dataSource.ExecuteAsync(_ => 42);
var result = task.Result;
So the first line kicks off the asynchronous work. The second line then blocks the UI thread. So when the runtime wants to run the "return result" line back on the UI thread, it can't do that until the Result completes. But of course, the Result can't be given until the return happens. Deadlock.
This illustrates a key rule of using the TPL: when you use .Result on a UI thread (or some other fancy sync context), you must be careful to ensure that nothing that Task is dependent upon is scheduled to the UI thread. Or else evilness happens.
So what do you do? Option #1 is use await everywhere, but as you said that's already not an option. Second option which is available for you is to simply stop using await. You can rewrite your two functions to:
public static Task<T> ExecuteAsync<T>(this OurDBConn dataSource, Func<OurDBConn, T> function)
{
string connectionString = dataSource.ConnectionString;
// Start the SQL and pass back to the caller until finished
return Task.Run(
() =>
{
// Copy the SQL connection so that we don't get two commands running at the same time on the same open connection
using (var ds = new OurDBConn(connectionString))
{
return function(ds);
}
});
}
public static Task<ResultClass> GetTotalAsync( ... )
{
return this.DBConnection.ExecuteAsync<ResultClass>(
ds => ds.Execute("select slow running data into result"));
}
What's the difference? There's now no awaiting anywhere, so nothing being implicitly scheduled to the UI thread. For simple methods like these that have a single return, there's no point in doing an "var result = await...; return result" pattern; just remove the async modifier and pass the task object around directly. It's less overhead, if nothing else.
Option #3 is to specify that you don't want your awaits to schedule back to the UI thread, but just schedule to the thread pool. You do this with the ConfigureAwait method, like so:
public static async Task<ResultClass> GetTotalAsync( ... )
{
var resultTask = this.DBConnection.ExecuteAsync<ResultClass>(
ds => return ds.Execute("select slow running data into result");
return await resultTask.ConfigureAwait(false);
}
Awaiting a task normally would schedule to the UI thread if you're on it; awaiting the result of ContinueAwait will ignore whatever context you are on, and always schedule to the threadpool. The downside of this is you have to sprinkle this everywhere in all functions your .Result depends on, because any missed .ConfigureAwait might be the cause of another deadlock.
This is the classic mixed-async deadlock scenario, as I describe on my blog. Jason described it well: by default, a "context" is saved at every await and used to continue the async method. This "context" is the current SynchronizationContext unless it it null, in which case it is the current TaskScheduler. When the async method attempts to continue, it first re-enters the captured "context" (in this case, an ASP.NET SynchronizationContext). The ASP.NET SynchronizationContext only permits one thread in the context at a time, and there is already a thread in the context - the thread blocked on Task.Result.
There are two guidelines that will avoid this deadlock:
Use async all the way down. You mention that you "can't" do this, but I'm not sure why not. ASP.NET MVC on .NET 4.5 can certainly support async actions, and it's not a difficult change to make.
Use ConfigureAwait(continueOnCapturedContext: false) as much as possible. This overrides the default behavior of resuming on the captured context.
I was in the same deadlock situation but in my case calling an async method from a sync method, what works for me was:
private static SiteMetadataCacheItem GetCachedItem()
{
TenantService TS = new TenantService(); // my service datacontext
var CachedItem = Task.Run(async ()=>
await TS.GetTenantDataAsync(TenantIdValue)
).Result; // dont deadlock anymore
}
is this a good approach, any idea?
Just to add to the accepted answer (not enough rep to comment), I had this issue arise when blocking using task.Result, event though every await below it had ConfigureAwait(false), as in this example:
public Foo GetFooSynchronous()
{
var foo = new Foo();
foo.Info = GetInfoAsync.Result; // often deadlocks in ASP.NET
return foo;
}
private async Task<string> GetInfoAsync()
{
return await ExternalLibraryStringAsync().ConfigureAwait(false);
}
The issue actually lay with the external library code. The async library method tried to continue in the calling sync context, no matter how I configured the await, leading to deadlock.
Thus, the answer was to roll my own version of the external library code ExternalLibraryStringAsync, so that it would have the desired continuation properties.
wrong answer for historical purposes
After much pain and anguish, I found the solution buried in this blog post (Ctrl-f for 'deadlock'). It revolves around using task.ContinueWith, instead of the bare task.Result.
Previously deadlocking example:
public Foo GetFooSynchronous()
{
var foo = new Foo();
foo.Info = GetInfoAsync.Result; // often deadlocks in ASP.NET
return foo;
}
private async Task<string> GetInfoAsync()
{
return await ExternalLibraryStringAsync().ConfigureAwait(false);
}
Avoid the deadlock like this:
public Foo GetFooSynchronous
{
var foo = new Foo();
GetInfoAsync() // ContinueWith doesn't run until the task is complete
.ContinueWith(task => foo.Info = task.Result);
return foo;
}
private async Task<string> GetInfoAsync
{
return await ExternalLibraryStringAsync().ConfigureAwait(false);
}
quick answer :
change this line
ResultClass slowTotal = asyncTask.Result;
to
ResultClass slowTotal = await asyncTask;
why? you should not use .result to get the result of tasks inside most applications except console applications if you do so your program will hang when it gets there
you can also try the below code if you want to use .Result
ResultClass slowTotal = Task.Run(async ()=>await asyncTask).Result;

How do I start not-awaited background tasks in an async method?

I'm struggling with how to perform some very-long-running background processing in a world of async methods.
Using the vocabulary from Stephen Cleary's blog, I'm interested in kicking off a "delegate task" after await-ing a "promise task". I want to return the promised value as soon as it's available, and let the delegate task continue on in the background.
To handle exceptions in the un-await-ed delegate task, I'll use an exception-handling continuation modeled after the one described here.
public async Task<int> ComplexProcessAsync()
{
...
int firstResult = await FirstStepAsync();
// THE COMPILER DOESN'T LIKE THIS
Task.Run(() => VeryLongSecondStepIDontNeedToWaitFor(firstResult)).LogExceptions();
return firstResult;
}
Since VeryLongSecondStep...() could take many minutes, and its results are observable purely by side-effect (e.g. records appearing in a database), I reeeaaalllyy don't want to await it.
But as pointed out, the compiler doesn't like this. It warns "Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call."
I could ignore the warning, but I get the feeling I'm not doing this in "correct" way. So what is the correct way?
Thanks!
I could ignore the warning, but I get the feeling I'm not doing this in "correct" way. So what is the correct way?
The compiler is warning you that you're not awaiting the task. From my experience, >99% of the time the compiler is correct, the code is wrong because it's missing an await. So this is one of the rare situations where you know what you're doing and want to live dangerously. :)
In this case, you can explicitly assign the task to an unused variable:
var _ = Task.Run(() => VeryLongSecondStepIDontNeedToWaitFor(firstResult));
The compiler is intelligent enough to understand that you're using this variable to silence the "missing await" warning.
On a side note, I do not recommend ContinueWith at all; in the async world, it's just a more dangerous version of await. So I'd write LogExceptions something like this:
public static async Task LogExceptions(this Task task)
{
try
{
await task.ConfigureAwait(false);
}
catch (Exception ex)
{
LogException(ex);
}
}
Since this is within an ASP.NET Web API app I suggest you use HostingEnvironment.QueueBackgroundWorkItem. Stephen Cleary also has a post about it.
HostingEnvironment.QueueBackgroundWorkItem(ct =>
{
try
{
// your code
}
catch (Exception ex)
{
// handle & log exception
}
});
https://msdn.microsoft.com/en-us/library/dn636893(v=vs.110).aspx
http://blog.stephencleary.com/2014/06/fire-and-forget-on-asp-net.html
The compiler is trying to protect you from mistakes because it's really easy to forget the await when you actually need to await something, but in this case you really don't need the await, so you can ignore the warning.
However, in this case I think it's a better idea to run the task on some thread from the threadpool, because if you're running it on the main thread like you're doing now, you might cause your application to be non-responsive for new incoming requests/events.
I'd like to suggest you to move VeryLongSecondStepIDontNeedToWaitFor() out of the ComplexProcessAsync() method.
ComplexProcessAsync() itself returns a value, that is being used by at least two tasks (one of them is Task.Run(() => VeryLongSecondStepIDontNeedToWaitFor(firstResult))).
You can combine these tasks via Task.WhenAny():
var result = await ComplexProcessAsync();
await Task.WhenAny(VeryLongSecondStepIDontNeedToWaitFor(firstResult), YourSecondMethod(firstResult))
where YourSecondMethod(firstResult) is the method that uses the ComplexProcessAsync() result.

Categories